io_uring/submit.rs
1use std::os::unix::io::{AsRawFd, RawFd};
2use std::sync::atomic;
3use std::{io, mem, ptr};
4
5use crate::register::{execute, Probe, RegisterRing};
6use crate::sys;
7use crate::types::{CancelBuilder, CloneBuffersFlags, Napi, Timespec};
8use crate::util::{cast_ptr, OwnedFd};
9use crate::Parameters;
10use bitflags::bitflags;
11
12use crate::register::Restriction;
13
14use crate::types;
15
16bitflags!(
17 /// See man page for complete description:
18 /// https://man7.org/linux/man-pages/man2/io_uring_enter.2.html
19 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
20 pub struct EnterFlags: u32 {
21 /// Wait for at least `min_complete` events to complete.
22 const GETEVENTS = sys::IORING_ENTER_GETEVENTS;
23
24 /// If the kernel thread is sleeping, wake it up.
25 const SQ_WAKEUP = sys::IORING_ENTER_SQ_WAKEUP;
26
27 /// Wait for at least one submission queue entry to be available.
28 const SQ_WAIT = sys::IORING_ENTER_SQ_WAIT;
29
30 /// Use the extended argument structure.
31 const EXT_ARG = sys::IORING_ENTER_EXT_ARG;
32
33 /// Submit using registered submission queue ring.
34 const REGISTERED_RING = sys::IORING_ENTER_REGISTERED_RING;
35
36 /// Timeout argument interpreted as absolute time.
37 const ABS_TIMER = sys::IORING_ENTER_ABS_TIMER;
38
39 /// Arg is offset into an area of wait regions previously registered.
40 const EXT_ARG_REG = sys::IORING_ENTER_EXT_ARG_REG;
41
42 /// Don't mark waiting task as being in iowait in certain cases.
43 const NO_IOWAIT = sys::IORING_ENTER_NO_IOWAIT;
44 }
45);
46
47/// Interface for submitting submission queue events in an io_uring instance to the kernel for
48/// executing and registering files or buffers with the instance.
49///
50/// io_uring supports both directly performing I/O on buffers and file descriptors and registering
51/// them beforehand. Registering is slow, but it makes performing the actual I/O much faster.
52pub struct Submitter<'a> {
53 fd: &'a OwnedFd,
54 params: &'a Parameters,
55 enter_ring_fd: i32,
56
57 sq_head: *const atomic::AtomicU32,
58 sq_tail: *const atomic::AtomicU32,
59 sq_flags: *const atomic::AtomicU32,
60}
61
62impl<'a> Submitter<'a> {
63 #[inline]
64 pub(crate) const fn new(
65 fd: &'a OwnedFd,
66 params: &'a Parameters,
67 sq_head: *const atomic::AtomicU32,
68 sq_tail: *const atomic::AtomicU32,
69 sq_flags: *const atomic::AtomicU32,
70 ) -> Submitter<'a> {
71 Submitter {
72 fd,
73 params,
74 enter_ring_fd: -1,
75 sq_head,
76 sq_tail,
77 sq_flags,
78 }
79 }
80
81 #[inline]
82 fn sq_len(&self) -> usize {
83 unsafe {
84 let head = (*self.sq_head).load(atomic::Ordering::Acquire);
85 let tail = (*self.sq_tail).load(atomic::Ordering::Acquire);
86
87 tail.wrapping_sub(head) as usize
88 }
89 }
90
91 /// Whether the kernel thread has gone to sleep because it waited for too long without
92 /// submission queue entries.
93 #[inline]
94 fn sq_need_wakeup(&self) -> bool {
95 unsafe {
96 (*self.sq_flags).load(atomic::Ordering::Relaxed) & sys::IORING_SQ_NEED_WAKEUP != 0
97 }
98 }
99
100 /// CQ ring is overflown
101 fn sq_cq_overflow(&self) -> bool {
102 unsafe {
103 (*self.sq_flags).load(atomic::Ordering::Relaxed) & sys::IORING_SQ_CQ_OVERFLOW != 0
104 }
105 }
106
107 #[inline]
108 fn execute_register(
109 &self,
110 opcode: libc::c_uint,
111 arg: *const libc::c_void,
112 len: libc::c_uint,
113 ) -> io::Result<i32> {
114 execute(self.register_ring(), opcode, arg, len)
115 }
116
117 #[inline]
118 fn register_ring(&self) -> RegisterRing {
119 let enter_ring_fd = self.enter_ring_fd;
120 if enter_ring_fd >= 0 && self.params.is_feature_reg_reg_ring() {
121 RegisterRing::RegisteredIndex(enter_ring_fd)
122 } else {
123 RegisterRing::RawFd(self.fd.as_raw_fd())
124 }
125 }
126
127 /// Initiate and/or complete asynchronous I/O. This is a low-level wrapper around
128 /// `io_uring_enter` - see `man io_uring_enter` (or [its online
129 /// version](https://manpages.debian.org/unstable/liburing-dev/io_uring_enter.2.en.html) for
130 /// more details.
131 ///
132 /// You will probably want to use a more high-level API such as
133 /// [`submit`](Self::submit) or [`submit_and_wait`](Self::submit_and_wait).
134 ///
135 /// # Safety
136 ///
137 /// This provides a raw interface so developer must ensure that parameters are correct.
138 pub unsafe fn enter<T: Sized>(
139 &self,
140 to_submit: u32,
141 min_complete: u32,
142 flag: u32,
143 arg: Option<&T>,
144 ) -> io::Result<usize> {
145 let arg = arg
146 .map(|arg| cast_ptr(arg).cast())
147 .unwrap_or_else(ptr::null);
148 let size = mem::size_of::<T>();
149
150 // If a ring fd has been registered with [`register_ring_fd`](Self::register_ring_fd),
151 // `enter_ring_fd` holds its index (otherwise `-1`); pass it together with
152 // `IORING_ENTER_REGISTERED_RING` instead of the raw file descriptor to avoid the per-call
153 // fd lookup in the kernel.
154 let enter_ring_fd = self.enter_ring_fd;
155 let (fd, flag) = if enter_ring_fd >= 0 {
156 (enter_ring_fd, flag | sys::IORING_ENTER_REGISTERED_RING)
157 } else {
158 (self.fd.as_raw_fd(), flag)
159 };
160
161 sys::io_uring_enter(fd, to_submit, min_complete, flag, arg, size).map(|res| res as _)
162 }
163
164 /// Submit all queued submission queue events to the kernel.
165 #[inline]
166 pub fn submit(&self) -> io::Result<usize> {
167 self.submit_and_wait(0)
168 }
169
170 /// Submit all queued submission queue events to the kernel and wait for at least `want`
171 /// completion events to complete.
172 pub fn submit_and_wait(&self, want: usize) -> io::Result<usize> {
173 let len = self.sq_len();
174 let mut flags = EnterFlags::empty();
175
176 // This logic suffers from the fact the sq_cq_overflow and sq_need_wakeup
177 // each cause an atomic load of the same variable, self.sq_flags.
178 // In the hottest paths, when a server is running with sqpoll,
179 // this is going to be hit twice, when once would be sufficient.
180 // However, consider that the `SeqCst` barrier required for interpreting
181 // the IORING_ENTER_SQ_WAKEUP bit is required in all paths where sqpoll
182 // is setup when consolidating the reads.
183
184 let sq_cq_overflow = self.sq_cq_overflow();
185
186 // When IORING_FEAT_NODROP is enabled and CQ overflows, the kernel buffers
187 // completion events internally but doesn't automatically flush them when
188 // CQ space becomes available. We must explicitly call io_uring_enter()
189 // to flush these buffered events, even with SQPOLL enabled.
190 //
191 // Without this, completions remain stuck in kernel's internal buffer
192 // after draining CQ, causing missing completion notifications.
193 let need_syscall_for_overflow = sq_cq_overflow && self.params.is_feature_nodrop();
194
195 if want > 0 || self.params.is_setup_iopoll() || sq_cq_overflow {
196 flags.insert(EnterFlags::GETEVENTS);
197 }
198
199 if self.params.is_setup_sqpoll() {
200 // See discussion in [`SubmissionQueue::need_wakeup`].
201 atomic::fence(atomic::Ordering::SeqCst);
202 if self.sq_need_wakeup() {
203 flags.insert(EnterFlags::SQ_WAKEUP);
204 } else if want == 0 && !need_syscall_for_overflow {
205 // The kernel thread is polling and hasn't fallen asleep, so we don't need to tell
206 // it to process events or wake it up
207
208 // However, if the CQ ring is overflown, we need to tell the kernel to process events
209 // by calling io_uring_enter with the IORING_ENTER_GETEVENTS flag.
210 return Ok(len);
211 }
212 }
213
214 unsafe { self.enter::<libc::sigset_t>(len as _, want as _, flags.bits(), None) }
215 }
216
217 /// Submit all queued submission queue events to the kernel and wait for at least `want`
218 /// completion events to complete with additional options
219 ///
220 /// You can specify a set of signals to mask and a timeout for operation, see
221 /// [`SubmitArgs`](types::SubmitArgs) for more details
222 pub fn submit_with_args(
223 &self,
224 want: usize,
225 args: &types::SubmitArgs<'_, '_>,
226 ) -> io::Result<usize> {
227 let len = self.sq_len();
228 let mut flags = EnterFlags::EXT_ARG;
229
230 let sq_cq_overflow = self.sq_cq_overflow();
231 let need_syscall = sq_cq_overflow & self.params.is_feature_nodrop();
232
233 if want > 0 || self.params.is_setup_iopoll() || sq_cq_overflow {
234 flags.insert(EnterFlags::GETEVENTS);
235 }
236
237 if self.params.is_setup_sqpoll() {
238 // See discussion in [`SubmissionQueue::need_wakeup`].
239 atomic::fence(atomic::Ordering::SeqCst);
240 if self.sq_need_wakeup() {
241 flags.insert(EnterFlags::SQ_WAKEUP);
242 } else if want == 0 && !need_syscall {
243 // The kernel thread is polling and hasn't fallen asleep, so we don't need to tell
244 // it to process events or wake it up
245 return Ok(len);
246 }
247 }
248
249 unsafe { self.enter(len as _, want as _, flags.bits(), Some(args)) }
250 }
251
252 /// Wait for the submission queue to have free entries.
253 pub fn squeue_wait(&self) -> io::Result<usize> {
254 unsafe { self.enter::<libc::sigset_t>(0, 0, EnterFlags::SQ_WAIT.bits(), None) }
255 }
256
257 /// Register in-memory fixed buffers for I/O with the kernel. You can use these buffers with the
258 /// [`ReadFixed`](crate::opcode::ReadFixed) and [`WriteFixed`](crate::opcode::WriteFixed)
259 /// operations.
260 ///
261 /// # Safety
262 ///
263 /// Developers must ensure that the `iov_base` and `iov_len` values are valid and will
264 /// be valid until buffers are unregistered or the ring destroyed, otherwise undefined
265 /// behaviour may occur.
266 pub unsafe fn register_buffers(&self, bufs: &[libc::iovec]) -> io::Result<()> {
267 self.execute_register(
268 sys::IORING_REGISTER_BUFFERS,
269 bufs.as_ptr().cast(),
270 bufs.len() as _,
271 )
272 .map(drop)
273 }
274
275 /// Update a range of fixed buffers starting at `offset`.
276 ///
277 /// This is required to use buffers registered using
278 /// [`register_buffers_sparse`](Self::register_buffers_sparse),
279 /// although it can be also be used with [`register_buffers`](Self::register_buffers).
280 ///
281 /// See [`register_buffers2`](Self::register_buffers2)
282 /// for more information about resource tagging.
283 ///
284 /// Available since Linux 5.13.
285 ///
286 /// # Safety
287 ///
288 /// Developers must ensure that the `iov_base` and `iov_len` values are valid and will
289 /// be valid until buffers are unregistered or the ring destroyed, otherwise undefined
290 /// behaviour may occur.
291 pub unsafe fn register_buffers_update(
292 &self,
293 offset: u32,
294 bufs: &[libc::iovec],
295 tags: Option<&[u64]>,
296 ) -> io::Result<()> {
297 let nr = tags
298 .as_ref()
299 .map_or(bufs.len(), |tags| bufs.len().min(tags.len()));
300
301 let rr = sys::io_uring_rsrc_update2 {
302 nr: nr as _,
303 data: bufs.as_ptr() as _,
304 tags: tags.map(|tags| tags.as_ptr() as _).unwrap_or(0),
305 offset,
306 ..Default::default()
307 };
308
309 self.execute_register(
310 sys::IORING_REGISTER_BUFFERS_UPDATE,
311 cast_ptr::<sys::io_uring_rsrc_update2>(&rr).cast(),
312 std::mem::size_of::<sys::io_uring_rsrc_update2>() as _,
313 )
314 .map(drop)
315 }
316
317 /// Variant of [`register_buffers`](Self::register_buffers)
318 /// with resource tagging.
319 ///
320 /// `tags` should be the same length as `bufs` and contain the
321 /// tag value corresponding to the buffer at the same index.
322 ///
323 /// If a tag is zero, then tagging for this particular resource
324 /// (a buffer in this case) is disabled. Otherwise, after the
325 /// resource had been unregistered and it's not used anymore,
326 /// a CQE will be posted with `user_data` set to the specified
327 /// tag and all other fields zeroed.
328 ///
329 /// Available since Linux 5.13.
330 ///
331 /// # Safety
332 ///
333 /// Developers must ensure that the `iov_base` and `iov_len` values are valid and will
334 /// be valid until buffers are unregistered or the ring destroyed, otherwise undefined
335 /// behaviour may occur.
336 pub unsafe fn register_buffers2(&self, bufs: &[libc::iovec], tags: &[u64]) -> io::Result<()> {
337 let rr = sys::io_uring_rsrc_register {
338 nr: bufs.len().min(tags.len()) as _,
339 data: bufs.as_ptr() as _,
340 tags: tags.as_ptr() as _,
341 ..Default::default()
342 };
343 self.execute_register(
344 sys::IORING_REGISTER_BUFFERS2,
345 cast_ptr::<sys::io_uring_rsrc_register>(&rr).cast(),
346 std::mem::size_of::<sys::io_uring_rsrc_register>() as _,
347 )
348 .map(drop)
349 }
350
351 /// Registers an empty table of nr fixed buffers buffers.
352 ///
353 /// These must be updated before use, using eg.
354 /// [`register_buffers_update`](Self::register_buffers_update).
355 ///
356 /// See [`register_buffers`](Self::register_buffers)
357 /// for more information about fixed buffers.
358 ///
359 /// Available since Linux 5.13.
360 pub fn register_buffers_sparse(&self, nr: u32) -> io::Result<()> {
361 let rr = sys::io_uring_rsrc_register {
362 nr,
363 flags: sys::IORING_RSRC_REGISTER_SPARSE,
364 ..Default::default()
365 };
366 self.execute_register(
367 sys::IORING_REGISTER_BUFFERS2,
368 cast_ptr::<sys::io_uring_rsrc_register>(&rr).cast(),
369 std::mem::size_of::<sys::io_uring_rsrc_register>() as _,
370 )
371 .map(drop)
372 }
373
374 /// Clone the entire registered buffer table from another ring into this one.
375 ///
376 /// `src_fd` is the raw file descriptor of the source `io_uring`. The source's
377 /// buffers are shared with this ring rather than copied, so a single physical
378 /// registration can back many rings without re-pinning the pages in the kernel.
379 ///
380 /// This ring's buffer table must be empty. To clone into a non-empty table or
381 /// to copy a sub-range, use
382 /// [`register_buffers_clone_offset`](Self::register_buffers_clone_offset).
383 ///
384 /// Available since Linux 6.12.
385 pub fn register_buffers_clone(&self, src_fd: RawFd) -> io::Result<()> {
386 self.register_buffers_clone_offset(src_fd, 0, 0, 0, CloneBuffersFlags::empty())
387 }
388
389 /// Clone a range of the registered buffer table from another ring into this one.
390 ///
391 /// `src_fd` is the raw file descriptor of the source `io_uring`. `nr` buffers
392 /// starting at `src_off` in the source table are installed starting at `dst_off`
393 /// in this ring's table. A `nr` of `0` clones the source's entire table.
394 ///
395 /// See [`CloneBuffersFlags`] for replacing an existing destination range or
396 /// treating `src_fd` as a registered ring descriptor.
397 ///
398 /// Available since Linux 6.12.
399 pub fn register_buffers_clone_offset(
400 &self,
401 src_fd: RawFd,
402 src_off: u32,
403 dst_off: u32,
404 nr: u32,
405 flags: CloneBuffersFlags,
406 ) -> io::Result<()> {
407 let arg = sys::io_uring_clone_buffers {
408 src_fd: src_fd as _,
409 flags: flags.bits(),
410 src_off,
411 dst_off,
412 nr,
413 ..Default::default()
414 };
415 execute(
416 RegisterRing::RawFd(self.fd.as_raw_fd()),
417 sys::IORING_REGISTER_CLONE_BUFFERS,
418 cast_ptr::<sys::io_uring_clone_buffers>(&arg).cast(),
419 // This opcode takes a single struct; the kernel requires nr_args == 1.
420 1,
421 )
422 .map(drop)
423 }
424
425 /// Registers an empty file table of nr_files number of file descriptors. The sparse variant is
426 /// available in kernels 5.19 and later.
427 ///
428 /// Registering a file table is a prerequisite for using any request that
429 /// uses direct descriptors.
430 pub fn register_files_sparse(&self, nr: u32) -> io::Result<()> {
431 let rr = sys::io_uring_rsrc_register {
432 nr,
433 flags: sys::IORING_RSRC_REGISTER_SPARSE,
434 resv2: 0,
435 data: 0,
436 tags: 0,
437 };
438 self.execute_register(
439 sys::IORING_REGISTER_FILES2,
440 cast_ptr::<sys::io_uring_rsrc_register>(&rr).cast(),
441 mem::size_of::<sys::io_uring_rsrc_register>() as _,
442 )
443 .map(drop)
444 }
445
446 /// Register files for I/O. You can use the registered files with
447 /// [`Fixed`](crate::types::Fixed).
448 ///
449 /// Each fd may be -1, in which case it is considered "sparse", and can be filled in later with
450 /// [`register_files_update`](Self::register_files_update).
451 ///
452 /// Note that this will wait for the ring to idle; it will only return once all active requests
453 /// are complete. Use [`register_files_update`](Self::register_files_update) to avoid this.
454 pub fn register_files(&self, fds: &[RawFd]) -> io::Result<()> {
455 self.execute_register(
456 sys::IORING_REGISTER_FILES,
457 fds.as_ptr().cast(),
458 fds.len() as _,
459 )
460 .map(drop)
461 }
462
463 /// This operation replaces existing files in the registered file set with new ones,
464 /// either turning a sparse entry (one where fd is equal to -1) into a real one, removing an existing entry (new one is set to -1),
465 /// or replacing an existing entry with a new existing entry. The `offset` parameter specifies
466 /// the offset into the list of registered files at which to start updating files.
467 ///
468 /// You can also perform this asynchronously with the
469 /// [`FilesUpdate`](crate::opcode::FilesUpdate) opcode.
470 pub fn register_files_update(&self, offset: u32, fds: &[RawFd]) -> io::Result<usize> {
471 let fu = sys::io_uring_files_update {
472 offset,
473 resv: 0,
474 fds: fds.as_ptr() as _,
475 };
476 let ret = self.execute_register(
477 sys::IORING_REGISTER_FILES_UPDATE,
478 cast_ptr::<sys::io_uring_files_update>(&fu).cast(),
479 fds.len() as _,
480 )?;
481 Ok(ret as _)
482 }
483
484 /// Register an eventfd created by [`eventfd`](libc::eventfd) with the io_uring instance.
485 pub fn register_eventfd(&self, eventfd: RawFd) -> io::Result<()> {
486 self.execute_register(
487 sys::IORING_REGISTER_EVENTFD,
488 cast_ptr::<RawFd>(&eventfd).cast(),
489 1,
490 )
491 .map(drop)
492 }
493
494 /// This works just like [`register_eventfd`](Self::register_eventfd), except notifications are
495 /// only posted for events that complete in an async manner, so requests that complete
496 /// immediately will not cause a notification.
497 pub fn register_eventfd_async(&self, eventfd: RawFd) -> io::Result<()> {
498 self.execute_register(
499 sys::IORING_REGISTER_EVENTFD_ASYNC,
500 cast_ptr::<RawFd>(&eventfd).cast(),
501 1,
502 )
503 .map(drop)
504 }
505
506 /// Fill in the given [`Probe`] with information about the opcodes supported by io_uring on the
507 /// running kernel.
508 ///
509 /// # Examples
510 ///
511 // This is marked no_run as it is only available from Linux 5.6+, however the latest Ubuntu (on
512 // which CI runs) only has Linux 5.4.
513 /// ```no_run
514 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
515 /// let io_uring = io_uring::IoUring::new(1)?;
516 /// let mut probe = io_uring::Probe::new();
517 /// io_uring.submitter().register_probe(&mut probe)?;
518 ///
519 /// if probe.is_supported(io_uring::opcode::Read::CODE) {
520 /// println!("Reading is supported!");
521 /// }
522 /// # Ok(())
523 /// # }
524 /// ```
525 pub fn register_probe(&self, probe: &mut Probe) -> io::Result<()> {
526 self.execute_register(
527 sys::IORING_REGISTER_PROBE,
528 probe.as_mut_ptr() as *const _,
529 Probe::COUNT as _,
530 )
531 .map(drop)
532 }
533
534 /// Register credentials of the running application with io_uring, and get an id associated with
535 /// these credentials. This ID can then be [passed](crate::squeue::Entry::personality) into
536 /// submission queue entries to issue the request with this process' credentials.
537 ///
538 /// By default, if [`Parameters::is_feature_cur_personality`] is set then requests will use the
539 /// credentials of the task that called [`Submitter::enter`], otherwise they will use the
540 /// credentials of the task that originally registered the io_uring.
541 ///
542 /// [`Parameters::is_feature_cur_personality`]: crate::Parameters::is_feature_cur_personality
543 pub fn register_personality(&self) -> io::Result<u16> {
544 let id = self.execute_register(sys::IORING_REGISTER_PERSONALITY, ptr::null(), 0)?;
545 Ok(id as u16)
546 }
547
548 /// Unregister all previously registered buffers.
549 ///
550 /// You do not need to explicitly call this before dropping the [`IoUring`](crate::IoUring), as
551 /// it will be cleaned up by the kernel automatically.
552 ///
553 /// Available since Linux 5.1.
554 pub fn unregister_buffers(&self) -> io::Result<()> {
555 self.execute_register(sys::IORING_UNREGISTER_BUFFERS, ptr::null(), 0)
556 .map(drop)
557 }
558
559 /// Unregister all previously registered files.
560 ///
561 /// You do not need to explicitly call this before dropping the [`IoUring`](crate::IoUring), as
562 /// it will be cleaned up by the kernel automatically.
563 pub fn unregister_files(&self) -> io::Result<()> {
564 self.execute_register(sys::IORING_UNREGISTER_FILES, ptr::null(), 0)
565 .map(drop)
566 }
567
568 /// Unregister an eventfd file descriptor to stop notifications.
569 pub fn unregister_eventfd(&self) -> io::Result<()> {
570 self.execute_register(sys::IORING_UNREGISTER_EVENTFD, ptr::null(), 0)
571 .map(drop)
572 }
573
574 /// Unregister a previously registered personality.
575 pub fn unregister_personality(&self, personality: u16) -> io::Result<()> {
576 self.execute_register(
577 sys::IORING_UNREGISTER_PERSONALITY,
578 ptr::null(),
579 personality as _,
580 )
581 .map(drop)
582 }
583
584 /// Permanently install a feature allowlist. Once this has been called, attempting to perform
585 /// an operation not on the allowlist will fail with `-EACCES`.
586 ///
587 /// This can only be called once, to prevent untrusted code from removing restrictions.
588 pub fn register_restrictions(&self, res: &mut [Restriction]) -> io::Result<()> {
589 self.execute_register(
590 sys::IORING_REGISTER_RESTRICTIONS,
591 res.as_mut_ptr().cast(),
592 res.len() as _,
593 )
594 .map(drop)
595 }
596
597 /// Enable the rings of the io_uring instance if they have been disabled with
598 /// [`setup_r_disabled`](crate::Builder::setup_r_disabled).
599 pub fn register_enable_rings(&self) -> io::Result<()> {
600 self.execute_register(sys::IORING_REGISTER_ENABLE_RINGS, ptr::null(), 0)
601 .map(drop)
602 }
603
604 /// Tell io_uring on what CPUs the async workers can run. By default, async workers
605 /// created by io_uring will inherit the CPU mask of its parent. This is usually
606 /// all the CPUs in the system, unless the parent is being run with a limited set.
607 pub fn register_iowq_aff(&self, cpu_set: &libc::cpu_set_t) -> io::Result<()> {
608 self.execute_register(
609 sys::IORING_REGISTER_IOWQ_AFF,
610 cpu_set as *const _ as *const libc::c_void,
611 mem::size_of::<libc::cpu_set_t>() as u32,
612 )
613 .map(drop)
614 }
615
616 /// Undoes a CPU mask previously set with register_iowq_aff
617 pub fn unregister_iowq_aff(&self) -> io::Result<()> {
618 self.execute_register(sys::IORING_UNREGISTER_IOWQ_AFF, ptr::null(), 0)
619 .map(drop)
620 }
621
622 /// Get and/or set the limit for number of io_uring worker threads per NUMA
623 /// node. `max[0]` holds the limit for bounded workers, which process I/O
624 /// operations expected to be bound in time, that is I/O on regular files or
625 /// block devices. While `max[1]` holds the limit for unbounded workers,
626 /// which carry out I/O operations that can never complete, for instance I/O
627 /// on sockets. Passing `0` does not change the current limit. Returns
628 /// previous limits on success.
629 pub fn register_iowq_max_workers(&self, max: &mut [u32; 2]) -> io::Result<()> {
630 self.execute_register(
631 sys::IORING_REGISTER_IOWQ_MAX_WORKERS,
632 max.as_mut_ptr().cast(),
633 max.len() as _,
634 )
635 .map(drop)
636 }
637
638 /// Register the io_uring instance's own file descriptor with the kernel, so that subsequent
639 /// [`enter`](Self::enter) calls (including [`submit`](Self::submit) and
640 /// [`submit_and_wait`](Self::submit_and_wait)) automatically pass
641 /// [`EnterFlags::REGISTERED_RING`] together with the registered index instead of the raw file
642 /// descriptor. This avoids the per-call file descriptor lookup overhead in the kernel.
643 ///
644 /// The registration is remembered by this [`Submitter`] and used transparently; call
645 /// [`unregister_ring_fd`](Self::unregister_ring_fd) on the same [`Submitter`] to undo it.
646 /// Calling this while a ring fd is already registered on this [`Submitter`] returns an `EEXIST`
647 /// error.
648 ///
649 /// On kernels with `IORING_FEAT_REG_REG_RING`, registration methods on this [`Submitter`] also
650 /// use the registered ring fd internally.
651 ///
652 /// Available since Linux 5.18.
653 pub fn register_ring_fd(&mut self) -> io::Result<()> {
654 if self.enter_ring_fd >= 0 {
655 return Err(io::Error::from_raw_os_error(libc::EEXIST));
656 }
657 let raw_fd = self.fd.as_raw_fd();
658 let mut up = sys::io_uring_rsrc_update {
659 offset: u32::MAX,
660 resv: 0,
661 data: raw_fd as _,
662 };
663 self.execute_register(
664 sys::IORING_REGISTER_RING_FDS,
665 (&mut up as *mut sys::io_uring_rsrc_update).cast(),
666 1,
667 )?;
668 self.enter_ring_fd = up.offset as i32;
669 Ok(())
670 }
671
672 /// Unregister a ring file descriptor previously registered with
673 /// [`register_ring_fd`](Self::register_ring_fd). Subsequent [`enter`](Self::enter) calls revert
674 /// to using the raw file descriptor, as do subsequent registration calls. Returns an `EINVAL`
675 /// error if no ring fd is registered.
676 ///
677 /// Available since Linux 5.18.
678 pub fn unregister_ring_fd(&mut self) -> io::Result<()> {
679 let offset = self.enter_ring_fd;
680 if offset < 0 {
681 return Err(io::Error::from_raw_os_error(libc::EINVAL));
682 }
683 let up = sys::io_uring_rsrc_update {
684 offset: offset as u32,
685 resv: 0,
686 data: 0,
687 };
688 self.execute_register(
689 sys::IORING_UNREGISTER_RING_FDS,
690 cast_ptr::<sys::io_uring_rsrc_update>(&up).cast(),
691 1,
692 )?;
693 self.enter_ring_fd = -1;
694 Ok(())
695 }
696
697 /// Register NAPI busy-poll settings on this ring.
698 ///
699 /// The kernel writes the previous settings back into `napi` before applying the new
700 /// ones; read them back with [`Napi::busy_poll_timeout`] and
701 /// [`Napi::prefer_busy_poll`].
702 ///
703 /// Available since Linux 6.9.
704 pub fn register_napi(&self, napi: &mut Napi) -> io::Result<()> {
705 self.execute_register(sys::IORING_REGISTER_NAPI, napi.as_mut_ptr().cast(), 1)
706 .map(drop)
707 }
708
709 /// Unregister NAPI busy-poll from this ring.
710 ///
711 /// The kernel writes the current settings back into `napi` before disabling them;
712 /// read them back with [`Napi::busy_poll_timeout`] and [`Napi::prefer_busy_poll`]. A
713 /// valid buffer is required, as the kernel rejects a null argument with `EINVAL`.
714 ///
715 /// Available since Linux 6.9.
716 pub fn unregister_napi(&self, napi: &mut Napi) -> io::Result<()> {
717 self.execute_register(sys::IORING_UNREGISTER_NAPI, napi.as_mut_ptr().cast(), 1)
718 .map(drop)
719 }
720
721 /// Add a NAPI id to this ring's statically tracked busy-poll set.
722 ///
723 /// The ring must already be registered with [`NapiTracking::Static`]; otherwise the
724 /// kernel returns an error. `napi_id` identifies a NIC receive-queue NAPI instance,
725 /// typically obtained from a socket via the `SO_INCOMING_NAPI_ID` socket option.
726 ///
727 /// [`NapiTracking::Static`]: crate::types::NapiTracking::Static
728 ///
729 /// Available since Linux 6.13.
730 pub fn register_napi_add_id(&self, napi_id: u32) -> io::Result<()> {
731 self.register_napi_static_op(sys::IO_URING_NAPI_STATIC_ADD_ID as _, napi_id)
732 }
733
734 /// Remove a NAPI id from this ring's statically tracked busy-poll set.
735 ///
736 /// The ring must already be registered with [`NapiTracking::Static`]; otherwise the
737 /// kernel returns an error. See [`register_napi_add_id`](Self::register_napi_add_id).
738 ///
739 /// [`NapiTracking::Static`]: crate::types::NapiTracking::Static
740 ///
741 /// Available since Linux 6.13.
742 pub fn register_napi_del_id(&self, napi_id: u32) -> io::Result<()> {
743 self.register_napi_static_op(sys::IO_URING_NAPI_STATIC_DEL_ID as _, napi_id)
744 }
745
746 fn register_napi_static_op(&self, opcode: u8, napi_id: u32) -> io::Result<()> {
747 // Both ops are issued through IORING_REGISTER_NAPI, distinguished by `opcode`,
748 // with the NAPI id carried in `op_param`. The kernel writes the current settings
749 // back into the struct, so pass a mutable pointer even though we discard them.
750 let mut arg = sys::io_uring_napi {
751 opcode,
752 op_param: napi_id,
753 ..Default::default()
754 };
755 self.execute_register(
756 sys::IORING_REGISTER_NAPI,
757 (&mut arg as *mut sys::io_uring_napi).cast(),
758 1,
759 )
760 .map(drop)
761 }
762
763 /// Register buffer ring for provided buffers.
764 ///
765 /// Details can be found in the io_uring_register_buf_ring.3 man page.
766 ///
767 /// If the register command is not supported, or the ring_entries value exceeds
768 /// 32768, the InvalidInput error is returned.
769 ///
770 /// Available since 5.19.
771 ///
772 /// # Safety
773 ///
774 /// Developers must ensure that the `ring_addr` and its length represented by `ring_entries`
775 /// are valid and will be valid until the bgid is unregistered or the ring destroyed,
776 /// otherwise undefined behaviour may occur.
777 #[deprecated(note = "please use `register_buf_ring_with_flags` instead")]
778 pub unsafe fn register_buf_ring(
779 &self,
780 ring_addr: u64,
781 ring_entries: u16,
782 bgid: u16,
783 ) -> io::Result<()> {
784 self.register_buf_ring_with_flags(ring_addr, ring_entries, bgid, 0)
785 }
786
787 /// Register buffer ring for provided buffers.
788 ///
789 /// Details can be found in the io_uring_register_buf_ring.3 man page.
790 ///
791 /// If the register command is not supported, or the ring_entries value exceeds
792 /// 32768, the InvalidInput error is returned.
793 ///
794 /// Available since 5.19.
795 ///
796 /// # Safety
797 ///
798 /// Developers must ensure that the `ring_addr` and its length represented by `ring_entries`
799 /// are valid and will be valid until the bgid is unregistered or the ring destroyed,
800 /// otherwise undefined behaviour may occur.
801 pub unsafe fn register_buf_ring_with_flags(
802 &self,
803 ring_addr: u64,
804 ring_entries: u16,
805 bgid: u16,
806 flags: u16,
807 ) -> io::Result<()> {
808 // The interface type for ring_entries is u32 but the same interface only allows a u16 for
809 // the tail to be specified, so to try and avoid further confusion, we limit the
810 // ring_entries to u16 here too. The value is actually limited to 2^15 (32768) but we can
811 // let the kernel enforce that.
812 let arg = sys::io_uring_buf_reg {
813 ring_addr,
814 ring_entries: ring_entries as _,
815 bgid,
816 flags,
817 ..Default::default()
818 };
819 self.execute_register(
820 sys::IORING_REGISTER_PBUF_RING,
821 cast_ptr::<sys::io_uring_buf_reg>(&arg).cast(),
822 1,
823 )
824 .map(drop)
825 }
826
827 /// Unregister a previously registered buffer ring.
828 ///
829 /// Available since 5.19.
830 pub fn unregister_buf_ring(&self, bgid: u16) -> io::Result<()> {
831 let arg = sys::io_uring_buf_reg {
832 ring_addr: 0,
833 ring_entries: 0,
834 bgid,
835 ..Default::default()
836 };
837 self.execute_register(
838 sys::IORING_UNREGISTER_PBUF_RING,
839 cast_ptr::<sys::io_uring_buf_reg>(&arg).cast(),
840 1,
841 )
842 .map(drop)
843 }
844
845 /// Performs a synchronous cancellation request, similar to [AsyncCancel](crate::opcode::AsyncCancel),
846 /// except that it completes synchronously.
847 ///
848 /// Cancellation can target a specific request, or all requests matching some criteria. The
849 /// [`CancelBuilder`] builder supports describing the match criteria for cancellation.
850 ///
851 /// An optional `timeout` can be provided to specify how long to wait for matched requests to be
852 /// canceled. If no timeout is provided, the default is to wait indefinitely.
853 ///
854 /// ### Errors
855 ///
856 /// If no requests are matched, returns:
857 ///
858 /// [io::ErrorKind::NotFound]: `No such file or directory (os error 2)`
859 ///
860 /// If a timeout is supplied, and the timeout elapses prior to all requests being canceled, returns:
861 ///
862 /// [io::ErrorKind::Uncategorized]: `Timer expired (os error 62)`
863 ///
864 /// ### Notes
865 ///
866 /// Only requests which have been submitted to the ring will be considered for cancellation. Requests
867 /// which have been written to the SQ, but not submitted, will not be canceled.
868 ///
869 /// Available since 6.0.
870 pub fn register_sync_cancel(
871 &self,
872 timeout: Option<Timespec>,
873 builder: CancelBuilder,
874 ) -> io::Result<()> {
875 let timespec = timeout.map(|ts| ts.0).unwrap_or(sys::__kernel_timespec {
876 tv_sec: -1,
877 tv_nsec: -1,
878 });
879 let user_data = builder.user_data.unwrap_or(0);
880 let flags = builder.flags.bits();
881 let fd = builder.to_fd();
882
883 let arg = sys::io_uring_sync_cancel_reg {
884 addr: user_data,
885 fd,
886 flags,
887 timeout: timespec,
888 ..Default::default()
889 };
890
891 self.execute_register(
892 sys::IORING_REGISTER_SYNC_CANCEL,
893 cast_ptr::<sys::io_uring_sync_cancel_reg>(&arg).cast(),
894 1,
895 )
896 .map(drop)
897 }
898
899 /// Register a netdev hw rx queue for zerocopy.
900 ///
901 /// Available since 6.15.
902 pub fn register_ifq(&self, reg: &sys::io_uring_zcrx_ifq_reg) -> io::Result<()> {
903 self.execute_register(
904 sys::IORING_REGISTER_ZCRX_IFQ,
905 cast_ptr::<sys::io_uring_zcrx_ifq_reg>(reg) as _,
906 1,
907 )
908 .map(drop)
909 }
910}