Skip to content

Commit c33e4f6

Browse files
authored
Update the io_uring module for Linux changes (#1341)
Add new opcodes `ReadMultishot`, `Waitid`, `FixedFdInstall`, `Ftruncate`, `Bind`, and `Listen`, and add support for `IoringFeatureFlags::RECVSEND_BUNDLE`. Also, use `io_uring_ptr` and `io_uring_user_data` instead of `u64` in more fields, to better preserve pointer provenance, and add more utility functions for working with `io_uring_ptr` and `io_uring_user_data`.
1 parent fdb524e commit c33e4f6

2 files changed

Lines changed: 184 additions & 17 deletions

File tree

src/io_uring/mod.rs

Lines changed: 183 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ mod bindgen_types;
2929
use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd};
3030
use crate::{backend, io};
3131
use bindgen_types::*;
32+
use core::cmp::Ordering;
3233
use core::ffi::c_void;
34+
use core::hash::{Hash, Hasher};
3335
use core::mem::MaybeUninit;
3436
use core::ptr::{null_mut, write_bytes};
3537
use linux_raw_sys::net;
@@ -428,6 +430,12 @@ pub enum IoringOp {
428430
/// `IORING_OP_SENDMSG_ZC`
429431
SendmsgZc = sys::io_uring_op::IORING_OP_SENDMSG_ZC as _,
430432

433+
/// `IORING_OP_READ_MULTISHOT`
434+
ReadMultishot = sys::io_uring_op::IORING_OP_READ_MULTISHOT as _,
435+
436+
/// `IORING_OP_WAITID`
437+
Waitid = sys::io_uring_op::IORING_OP_WAITID as _,
438+
431439
/// `IORING_OP_FUTEX_WAIT`
432440
FutexWait = sys::io_uring_op::IORING_OP_FUTEX_WAIT as _,
433441

@@ -436,6 +444,18 @@ pub enum IoringOp {
436444

437445
/// `IORING_OP_FUTEX_WAITV`
438446
FutexWaitv = sys::io_uring_op::IORING_OP_FUTEX_WAITV as _,
447+
448+
/// `IORING_OP_FIXED_FD_INSTALL`
449+
FixedFdInstall = sys::io_uring_op::IORING_OP_FIXED_FD_INSTALL as _,
450+
451+
/// `IORING_OP_FTRUNCATE`
452+
Ftruncate = sys::io_uring_op::IORING_OP_FTRUNCATE as _,
453+
454+
/// `IORING_OP_BIND`
455+
Bind = sys::io_uring_op::IORING_OP_BIND as _,
456+
457+
/// `IORING_OP_LISTEN`
458+
Listen = sys::io_uring_op::IORING_OP_LISTEN as _,
439459
}
440460

441461
impl Default for IoringOp {
@@ -714,6 +734,19 @@ bitflags::bitflags! {
714734
}
715735
}
716736

737+
bitflags::bitflags! {
738+
/// `IORING_FIXED_FD_*` flags for use with [`io_uring_sqe`].
739+
#[repr(transparent)]
740+
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
741+
pub struct IoringFixedFdFlags: u32 {
742+
/// `IORING_FIXED_FD_NO_CLOEXEC`
743+
const NO_CLOEXEC = sys::IORING_FIXED_FD_NO_CLOEXEC;
744+
745+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
746+
const _ = !0;
747+
}
748+
}
749+
717750
bitflags::bitflags! {
718751
/// `IORING_FEAT_*` flags for use with [`io_uring_params`].
719752
#[repr(transparent)]
@@ -761,6 +794,9 @@ bitflags::bitflags! {
761794
/// `IORING_FEAT_REG_REG_RING`
762795
const REG_REG_RING = sys::IORING_FEAT_REG_REG_RING;
763796

797+
/// `IORING_FEAT_RECVSEND_BUNDLE`
798+
const RECVSEND_BUNDLE = sys::IORING_FEAT_RECVSEND_BUNDLE;
799+
764800
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
765801
const _ = !0;
766802
}
@@ -864,6 +900,11 @@ bitflags::bitflags! {
864900
/// `IORING_SEND_ZC_REPORT_USAGE` (since Linux 6.2)
865901
const ZC_REPORT_USAGE = sys::IORING_SEND_ZC_REPORT_USAGE as _;
866902

903+
/// `IORING_RECVSEND_BUNDLE`
904+
///
905+
/// See also [`IoringRecvFlags::BUNDLE`].
906+
const BUNDLE = sys::IORING_RECVSEND_BUNDLE as _;
907+
867908
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
868909
const _ = !0;
869910
}
@@ -887,6 +928,11 @@ bitflags::bitflags! {
887928
/// See also [`IoringSendFlags::FIXED_BUF`].
888929
const FIXED_BUF = sys::IORING_RECVSEND_FIXED_BUF as _;
889930

931+
/// `IORING_RECVSEND_BUNDLE`
932+
///
933+
/// See also [`IoringSendFlags::BUNDLE`].
934+
const BUNDLE = sys::IORING_RECVSEND_BUNDLE as _;
935+
890936
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
891937
const _ = !0;
892938
}
@@ -981,24 +1027,74 @@ pub struct io_uring_ptr {
9811027
pub __pad32: u32,
9821028
}
9831029

984-
impl From<*mut c_void> for io_uring_ptr {
1030+
impl io_uring_ptr {
1031+
/// Construct a null `io_uring_ptr`.
9851032
#[inline]
986-
fn from(ptr: *mut c_void) -> Self {
1033+
pub const fn null() -> Self {
1034+
Self::new(null_mut())
1035+
}
1036+
1037+
/// Construct a new `io_uring_ptr`.
1038+
#[inline]
1039+
pub const fn new(ptr: *mut c_void) -> Self {
9871040
Self {
9881041
ptr,
9891042

9901043
#[cfg(target_pointer_width = "16")]
991-
__pad16: Default::default(),
1044+
__pad16: 0,
9921045
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
993-
__pad32: Default::default(),
1046+
__pad32: 0,
9941047
}
9951048
}
9961049
}
9971050

1051+
impl From<*mut c_void> for io_uring_ptr {
1052+
#[inline]
1053+
fn from(ptr: *mut c_void) -> Self {
1054+
Self::new(ptr)
1055+
}
1056+
}
1057+
1058+
impl PartialEq for io_uring_ptr {
1059+
#[inline]
1060+
fn eq(&self, other: &Self) -> bool {
1061+
self.ptr.eq(&other.ptr)
1062+
}
1063+
}
1064+
1065+
impl Eq for io_uring_ptr {}
1066+
1067+
impl PartialOrd for io_uring_ptr {
1068+
#[inline]
1069+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1070+
self.ptr.partial_cmp(&other.ptr)
1071+
}
1072+
}
1073+
1074+
impl Ord for io_uring_ptr {
1075+
#[inline]
1076+
fn cmp(&self, other: &Self) -> Ordering {
1077+
self.ptr.cmp(&other.ptr)
1078+
}
1079+
}
1080+
1081+
impl Hash for io_uring_ptr {
1082+
#[inline]
1083+
fn hash<H: Hasher>(&self, state: &mut H) {
1084+
self.ptr.hash(state)
1085+
}
1086+
}
1087+
9981088
impl Default for io_uring_ptr {
9991089
#[inline]
10001090
fn default() -> Self {
1001-
Self::from(null_mut())
1091+
Self::null()
1092+
}
1093+
}
1094+
1095+
impl core::fmt::Pointer for io_uring_ptr {
1096+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1097+
self.ptr.fmt(f)
10021098
}
10031099
}
10041100

@@ -1026,33 +1122,81 @@ pub union io_uring_user_data {
10261122
impl io_uring_user_data {
10271123
/// Return the `u64` value.
10281124
#[inline]
1029-
pub fn u64_(self) -> u64 {
1125+
pub const fn u64_(self) -> u64 {
10301126
// SAFETY: All the fields have the same underlying representation.
10311127
unsafe { self.u64_ }
10321128
}
10331129

10341130
/// Create a `Self` from a `u64` value.
10351131
#[inline]
1036-
pub fn from_u64(u64_: u64) -> Self {
1132+
pub const fn from_u64(u64_: u64) -> Self {
10371133
Self { u64_ }
10381134
}
10391135

10401136
/// Return the `ptr` pointer value.
10411137
#[inline]
1042-
pub fn ptr(self) -> *mut c_void {
1138+
pub const fn ptr(self) -> *mut c_void {
10431139
// SAFETY: All the fields have the same underlying representation.
10441140
unsafe { self.ptr }.ptr
10451141
}
10461142

10471143
/// Create a `Self` from a pointer value.
10481144
#[inline]
1049-
pub fn from_ptr(ptr: *mut c_void) -> Self {
1145+
pub const fn from_ptr(ptr: *mut c_void) -> Self {
10501146
Self {
1051-
ptr: io_uring_ptr::from(ptr),
1147+
ptr: io_uring_ptr::new(ptr),
10521148
}
10531149
}
10541150
}
10551151

1152+
impl From<u64> for io_uring_user_data {
1153+
#[inline]
1154+
fn from(u64_: u64) -> Self {
1155+
Self::from_u64(u64_)
1156+
}
1157+
}
1158+
1159+
impl From<*mut c_void> for io_uring_user_data {
1160+
#[inline]
1161+
fn from(ptr: *mut c_void) -> Self {
1162+
Self::from_ptr(ptr)
1163+
}
1164+
}
1165+
1166+
impl PartialEq for io_uring_user_data {
1167+
#[inline]
1168+
fn eq(&self, other: &Self) -> bool {
1169+
// SAFETY: `io_uring_ptr` and `u64` have the same layout.
1170+
unsafe { self.u64_.eq(&other.u64_) }
1171+
}
1172+
}
1173+
1174+
impl Eq for io_uring_user_data {}
1175+
1176+
impl PartialOrd for io_uring_user_data {
1177+
#[inline]
1178+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1179+
// SAFETY: `io_uring_ptr` and `u64` have the same layout.
1180+
unsafe { self.u64_.partial_cmp(&other.u64_) }
1181+
}
1182+
}
1183+
1184+
impl Ord for io_uring_user_data {
1185+
#[inline]
1186+
fn cmp(&self, other: &Self) -> Ordering {
1187+
// SAFETY: `io_uring_ptr` and `u64` have the same layout.
1188+
unsafe { self.u64_.cmp(&other.u64_) }
1189+
}
1190+
}
1191+
1192+
impl Hash for io_uring_user_data {
1193+
#[inline]
1194+
fn hash<H: Hasher>(&self, state: &mut H) {
1195+
// SAFETY: `io_uring_ptr` and `u64` have the same layout.
1196+
unsafe { self.u64_.hash(state) }
1197+
}
1198+
}
1199+
10561200
impl Default for io_uring_user_data {
10571201
#[inline]
10581202
fn default() -> Self {
@@ -1188,6 +1332,7 @@ pub union op_flags_union {
11881332
pub msg_ring_flags: IoringMsgringFlags,
11891333
pub uring_cmd_flags: IoringUringCmdFlags,
11901334
pub futex_flags: FutexWaitvFlags,
1335+
pub install_fd_flags: IoringFixedFdFlags,
11911336
}
11921337

11931338
#[allow(missing_docs)]
@@ -1222,7 +1367,7 @@ pub struct addr_len_struct {
12221367
#[derive(Copy, Clone)]
12231368
#[non_exhaustive]
12241369
pub struct io_uring_sync_cancel_reg {
1225-
pub addr: u64,
1370+
pub addr: io_uring_user_data,
12261371
pub fd: i32,
12271372
pub flags: IoringAsyncCancelFlags,
12281373
pub timeout: Timespec,
@@ -1312,7 +1457,7 @@ pub struct io_sqring_offsets {
13121457
pub dropped: u32,
13131458
pub array: u32,
13141459
pub resv1: u32,
1315-
pub user_addr: u64,
1460+
pub user_addr: io_uring_ptr,
13161461
}
13171462

13181463
#[allow(missing_docs)]
@@ -1327,7 +1472,7 @@ pub struct io_cqring_offsets {
13271472
pub cqes: u32,
13281473
pub flags: u32,
13291474
pub resv1: u32,
1330-
pub user_addr: u64,
1475+
pub user_addr: io_uring_ptr,
13311476
}
13321477

13331478
#[allow(missing_docs)]
@@ -1437,7 +1582,7 @@ pub struct open_how {
14371582
#[repr(C)]
14381583
#[derive(Debug, Copy, Clone, Default)]
14391584
pub struct io_uring_buf_reg {
1440-
pub ring_addr: u64,
1585+
pub ring_addr: io_uring_ptr,
14411586
pub ring_entries: u32,
14421587
pub bgid: u16,
14431588
pub flags: u16,
@@ -1448,7 +1593,7 @@ pub struct io_uring_buf_reg {
14481593
#[repr(C)]
14491594
#[derive(Debug, Copy, Clone, Default)]
14501595
pub struct io_uring_buf {
1451-
pub addr: u64,
1596+
pub addr: io_uring_ptr,
14521597
pub len: u32,
14531598
pub bid: u16,
14541599
pub resv: u16,
@@ -1568,7 +1713,7 @@ mod tests {
15681713
// io_uring stores them in a `u64`.
15691714
unsafe {
15701715
const MAGIC: u64 = !0x0123456789abcdef;
1571-
let ptr = io_uring_ptr::from(MAGIC as usize as *mut c_void);
1716+
let ptr = io_uring_ptr::new(MAGIC as usize as *mut c_void);
15721717
assert_eq!(ptr.ptr, MAGIC as usize as *mut c_void);
15731718
#[cfg(target_pointer_width = "16")]
15741719
assert_eq!(ptr.__pad16, 0);
@@ -1578,6 +1723,28 @@ mod tests {
15781723
assert_eq!(int, MAGIC as usize as u64);
15791724
}
15801725

1726+
// `io_uring_user_data` is a replacement for `u64`.
1727+
assert_eq_size!(io_uring_user_data, u64);
1728+
assert_eq_align!(io_uring_user_data, u64);
1729+
1730+
// Test that `u64`s and pointers are properly stored in
1731+
// io_uring_user_data`.
1732+
unsafe {
1733+
const MAGIC: u64 = !0x0123456789abcdef;
1734+
let user_data = io_uring_user_data::from_u64(MAGIC);
1735+
assert_eq!(user_data.u64_(), MAGIC);
1736+
assert_eq!(
1737+
core::mem::transmute::<io_uring_user_data, u64>(user_data),
1738+
MAGIC
1739+
);
1740+
let user_data = io_uring_user_data::from_ptr(MAGIC as usize as *mut c_void);
1741+
assert_eq!(user_data.ptr(), MAGIC as usize as *mut c_void);
1742+
assert_eq!(
1743+
core::mem::transmute::<io_uring_user_data, u64>(user_data),
1744+
MAGIC as usize as u64
1745+
);
1746+
}
1747+
15811748
check_renamed_type!(off_or_addr2_union, io_uring_sqe__bindgen_ty_1);
15821749
check_renamed_type!(addr_or_splice_off_in_union, io_uring_sqe__bindgen_ty_2);
15831750
check_renamed_type!(addr3_or_cmd_union, io_uring_sqe__bindgen_ty_6);

tests/io_uring/register.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ fn io_uring_buf_ring_can_be_registered() {
158158
let br = unsafe { br_ptr.as_mut() }.expect("A valid io_uring_buf_ring struct");
159159

160160
let reg = io_uring_buf_reg {
161-
ring_addr: br_ptr as u64,
161+
ring_addr: br_ptr.cast::<c_void>().into(),
162162
ring_entries: ENTRIES as u32,
163163
bgid: BGID,
164164
flags: 0,

0 commit comments

Comments
 (0)