Skip to content

Commit 0c2061c

Browse files
ryanseippsunfishcode
authored andcommitted
Add io_uring_buf_ring struct (#1155)
1 parent ffcdad7 commit 0c2061c

File tree

2 files changed

+114
-3
lines changed

2 files changed

+114
-3
lines changed

Diff for: src/io_uring.rs

+44
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,39 @@ pub struct io_uring_buf {
14331433
pub resv: u16,
14341434
}
14351435

1436+
#[allow(missing_docs)]
1437+
#[repr(C)]
1438+
#[derive(Debug, Copy, Clone, Default)]
1439+
pub struct buf_ring_tail_struct {
1440+
pub resv1: u64,
1441+
pub resv2: u32,
1442+
pub resv3: u16,
1443+
pub tail: u16,
1444+
}
1445+
1446+
#[allow(missing_docs)]
1447+
#[repr(C)]
1448+
#[derive(Debug, Default)]
1449+
pub struct buf_ring_bufs_struct {
1450+
pub bufs: sys::__IncompleteArrayField<io_uring_buf>,
1451+
}
1452+
1453+
#[allow(missing_docs)]
1454+
#[repr(C)]
1455+
#[derive(Debug, Default)]
1456+
pub struct tail_or_bufs_struct {
1457+
pub tail: sys::__BindgenUnionField<buf_ring_tail_struct>,
1458+
pub bufs: sys::__BindgenUnionField<buf_ring_bufs_struct>,
1459+
pub union_field: [u64; 2],
1460+
}
1461+
1462+
#[allow(missing_docs)]
1463+
#[repr(C)]
1464+
#[derive(Debug, Default)]
1465+
pub struct io_uring_buf_ring {
1466+
pub tail_or_bufs: tail_or_bufs_struct,
1467+
}
1468+
14361469
impl Default for ioprio_union {
14371470
#[inline]
14381471
fn default() -> Self {
@@ -1599,5 +1632,16 @@ mod tests {
15991632
check_struct!(io_uring_buf_reg, ring_addr, ring_entries, bgid, pad, resv);
16001633
check_struct!(io_uring_buf, addr, len, bid, resv);
16011634
check_struct!(io_uring_sync_cancel_reg, addr, fd, flags, timeout, pad);
1635+
1636+
check_renamed_type!(tail_or_bufs_struct, io_uring_buf_ring__bindgen_ty_1);
1637+
check_renamed_type!(
1638+
buf_ring_tail_struct,
1639+
io_uring_buf_ring__bindgen_ty_1__bindgen_ty_1
1640+
);
1641+
check_renamed_type!(
1642+
buf_ring_bufs_struct,
1643+
io_uring_buf_ring__bindgen_ty_1__bindgen_ty_2
1644+
);
1645+
check_struct_renamed_field!(io_uring_buf_ring, tail_or_bufs, __bindgen_anon_1);
16021646
}
16031647
}

Diff for: tests/io_uring/register.rs

+70-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use std::ptr;
2+
13
use libc::c_void;
24
use rustix::fd::{AsFd, AsRawFd, BorrowedFd};
3-
use rustix::io::Result;
5+
use rustix::io::{Errno, Result};
46
use rustix::io_uring::{
5-
io_uring_params, io_uring_register_with, io_uring_rsrc_update, io_uring_setup,
6-
IoringFeatureFlags, IoringRegisterFlags, IoringRegisterOp,
7+
io_uring_buf, io_uring_buf_reg, io_uring_buf_ring, io_uring_params, io_uring_register_with,
8+
io_uring_rsrc_update, io_uring_setup, IoringFeatureFlags, IoringRegisterFlags,
9+
IoringRegisterOp,
710
};
11+
use rustix::mm::{MapFlags, ProtFlags};
812

913
fn do_register<FD>(
1014
fd: FD,
@@ -87,6 +91,19 @@ where
8791
Ok(())
8892
}
8993

94+
fn register_buf_ring<FD>(fd: FD, reg: &io_uring_buf_reg) -> Result<()>
95+
where
96+
FD: AsFd,
97+
{
98+
do_register(
99+
fd,
100+
false,
101+
IoringRegisterOp::RegisterPbufRing,
102+
reg as *const io_uring_buf_reg as *const c_void,
103+
1,
104+
)
105+
}
106+
90107
#[test]
91108
fn test_io_uring_register_with() {
92109
let mut params = io_uring_params::default();
@@ -104,3 +121,53 @@ fn test_io_uring_register_with() {
104121
unregister_ring(ring_fd).unwrap();
105122
register_result.unwrap();
106123
}
124+
125+
#[test]
126+
fn io_uring_buf_ring_can_be_registered() {
127+
const ENTRIES: usize = 8;
128+
const BGID: u16 = 42;
129+
130+
let mut params = io_uring_params::default();
131+
let ring_fd = io_uring_setup(4, &mut params).unwrap();
132+
133+
// Test that the kernel version supports IORING_REGISTER_PBUF_RING. If it doesn't, the kernel
134+
// will return EINVAL. Not setting a `ring_addr` on `io_uring_buf_reg` will return `EFAULT`.
135+
if let Err(e) = register_buf_ring(ring_fd.as_fd(), &io_uring_buf_reg::default()) {
136+
if e == Errno::INVAL {
137+
// Skip the test, as the current kernel version doesn't support what we need to test.
138+
return;
139+
}
140+
}
141+
142+
let buf_ring_size = ENTRIES * std::mem::size_of::<io_uring_buf>();
143+
144+
let br_ptr = unsafe {
145+
rustix::mm::mmap_anonymous(
146+
ptr::null_mut(),
147+
buf_ring_size,
148+
ProtFlags::READ | ProtFlags::WRITE,
149+
MapFlags::PRIVATE,
150+
)
151+
}
152+
.unwrap() as *mut io_uring_buf_ring;
153+
154+
let br = unsafe { br_ptr.as_mut() }.expect("A valid io_uring_buf_ring struct");
155+
156+
let reg = io_uring_buf_reg {
157+
ring_addr: br_ptr as u64,
158+
ring_entries: ENTRIES as u32,
159+
bgid: BGID,
160+
pad: 0,
161+
resv: [0u64; 3],
162+
};
163+
164+
assert_eq!(register_buf_ring(ring_fd, &reg), Ok(()));
165+
166+
let tail = unsafe { br.tail_or_bufs.tail.as_mut() };
167+
tail.tail = 0;
168+
let bufs = unsafe { br.tail_or_bufs.bufs.as_mut().bufs.as_mut_slice(ENTRIES) };
169+
170+
assert_eq!(bufs[0].bid, 0);
171+
bufs[7].bid = 7;
172+
assert_eq!(bufs[7].bid, 7);
173+
}

0 commit comments

Comments
 (0)