1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(any(target_os = "android", target_os = "linux"))]
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeSet;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::io::IoSlice;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::io::IoSliceMut;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Seek;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::io::SeekFrom;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
17*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::AsRawFd;
18*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::RawFd;
19*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
20*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
21*bb4ee6a4SAndroid Build Coastguard Worker use std::pin::Pin;
22*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicUsize;
23*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
24*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::channel;
25*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
26*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Barrier;
27*bb4ee6a4SAndroid Build Coastguard Worker use std::thread;
28*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
29*bb4ee6a4SAndroid Build Coastguard Worker
30*bb4ee6a4SAndroid Build Coastguard Worker use base::pipe;
31*bb4ee6a4SAndroid Build Coastguard Worker use base::EventType;
32*bb4ee6a4SAndroid Build Coastguard Worker use base::IoBufMut;
33*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
34*bb4ee6a4SAndroid Build Coastguard Worker use io_uring::Error;
35*bb4ee6a4SAndroid Build Coastguard Worker use io_uring::URingAllowlist;
36*bb4ee6a4SAndroid Build Coastguard Worker use io_uring::URingContext;
37*bb4ee6a4SAndroid Build Coastguard Worker use io_uring::UserData;
38*bb4ee6a4SAndroid Build Coastguard Worker use libc::EACCES;
39*bb4ee6a4SAndroid Build Coastguard Worker use sync::Condvar;
40*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
41*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::tempfile;
42*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::TempDir;
43*bb4ee6a4SAndroid Build Coastguard Worker
append_file_name(path: &Path, name: &str) -> PathBuf44*bb4ee6a4SAndroid Build Coastguard Worker fn append_file_name(path: &Path, name: &str) -> PathBuf {
45*bb4ee6a4SAndroid Build Coastguard Worker let mut joined = path.to_path_buf();
46*bb4ee6a4SAndroid Build Coastguard Worker joined.push(name);
47*bb4ee6a4SAndroid Build Coastguard Worker joined
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker
50*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
51*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
add_one_read( uring: &URingContext, ptr: *mut u8, len: usize, fd: RawFd, offset: Option<u64>, user_data: UserData, ) -> Result<(), Error>52*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn add_one_read(
53*bb4ee6a4SAndroid Build Coastguard Worker uring: &URingContext,
54*bb4ee6a4SAndroid Build Coastguard Worker ptr: *mut u8,
55*bb4ee6a4SAndroid Build Coastguard Worker len: usize,
56*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
57*bb4ee6a4SAndroid Build Coastguard Worker offset: Option<u64>,
58*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
59*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(), Error> {
60*bb4ee6a4SAndroid Build Coastguard Worker uring.add_readv(
61*bb4ee6a4SAndroid Build Coastguard Worker Pin::from(vec![IoBufMut::from_raw_parts(ptr, len)].into_boxed_slice()),
62*bb4ee6a4SAndroid Build Coastguard Worker fd,
63*bb4ee6a4SAndroid Build Coastguard Worker offset,
64*bb4ee6a4SAndroid Build Coastguard Worker user_data,
65*bb4ee6a4SAndroid Build Coastguard Worker )
66*bb4ee6a4SAndroid Build Coastguard Worker }
67*bb4ee6a4SAndroid Build Coastguard Worker
68*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
69*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
add_one_write( uring: &URingContext, ptr: *const u8, len: usize, fd: RawFd, offset: Option<u64>, user_data: UserData, ) -> Result<(), Error>70*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn add_one_write(
71*bb4ee6a4SAndroid Build Coastguard Worker uring: &URingContext,
72*bb4ee6a4SAndroid Build Coastguard Worker ptr: *const u8,
73*bb4ee6a4SAndroid Build Coastguard Worker len: usize,
74*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
75*bb4ee6a4SAndroid Build Coastguard Worker offset: Option<u64>,
76*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
77*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(), Error> {
78*bb4ee6a4SAndroid Build Coastguard Worker uring.add_writev(
79*bb4ee6a4SAndroid Build Coastguard Worker Pin::from(vec![IoBufMut::from_raw_parts(ptr as *mut u8, len)].into_boxed_slice()),
80*bb4ee6a4SAndroid Build Coastguard Worker fd,
81*bb4ee6a4SAndroid Build Coastguard Worker offset,
82*bb4ee6a4SAndroid Build Coastguard Worker user_data,
83*bb4ee6a4SAndroid Build Coastguard Worker )
84*bb4ee6a4SAndroid Build Coastguard Worker }
85*bb4ee6a4SAndroid Build Coastguard Worker
create_test_file(size: u64) -> std::fs::File86*bb4ee6a4SAndroid Build Coastguard Worker fn create_test_file(size: u64) -> std::fs::File {
87*bb4ee6a4SAndroid Build Coastguard Worker let f = tempfile().unwrap();
88*bb4ee6a4SAndroid Build Coastguard Worker f.set_len(size).unwrap();
89*bb4ee6a4SAndroid Build Coastguard Worker f
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker
92*bb4ee6a4SAndroid Build Coastguard Worker #[test]
93*bb4ee6a4SAndroid Build Coastguard Worker // Queue as many reads as possible and then collect the completions.
read_parallel()94*bb4ee6a4SAndroid Build Coastguard Worker fn read_parallel() {
95*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: usize = 10;
96*bb4ee6a4SAndroid Build Coastguard Worker const BUF_SIZE: usize = 0x1000;
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(QUEUE_SIZE, None).unwrap();
99*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; BUF_SIZE * QUEUE_SIZE];
100*bb4ee6a4SAndroid Build Coastguard Worker let f = create_test_file((BUF_SIZE * QUEUE_SIZE) as u64);
101*bb4ee6a4SAndroid Build Coastguard Worker
102*bb4ee6a4SAndroid Build Coastguard Worker // check that the whole file can be read and that the queues wrapping is handled by reading
103*bb4ee6a4SAndroid Build Coastguard Worker // double the quue depth of buffers.
104*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..QUEUE_SIZE * 64 {
105*bb4ee6a4SAndroid Build Coastguard Worker let index = i as u64;
106*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
107*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
108*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
109*bb4ee6a4SAndroid Build Coastguard Worker let offset = (i % QUEUE_SIZE) * BUF_SIZE;
110*bb4ee6a4SAndroid Build Coastguard Worker match add_one_read(
111*bb4ee6a4SAndroid Build Coastguard Worker &uring,
112*bb4ee6a4SAndroid Build Coastguard Worker buf[offset..].as_mut_ptr(),
113*bb4ee6a4SAndroid Build Coastguard Worker BUF_SIZE,
114*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
115*bb4ee6a4SAndroid Build Coastguard Worker Some(offset as u64),
116*bb4ee6a4SAndroid Build Coastguard Worker index,
117*bb4ee6a4SAndroid Build Coastguard Worker ) {
118*bb4ee6a4SAndroid Build Coastguard Worker Ok(_) => (),
119*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::NoSpace) => {
120*bb4ee6a4SAndroid Build Coastguard Worker let _ = uring.wait().unwrap().next().unwrap();
121*bb4ee6a4SAndroid Build Coastguard Worker }
122*bb4ee6a4SAndroid Build Coastguard Worker Err(_) => panic!("unexpected error from uring wait"),
123*bb4ee6a4SAndroid Build Coastguard Worker }
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker }
126*bb4ee6a4SAndroid Build Coastguard Worker }
127*bb4ee6a4SAndroid Build Coastguard Worker
128*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_readv()129*bb4ee6a4SAndroid Build Coastguard Worker fn read_readv() {
130*bb4ee6a4SAndroid Build Coastguard Worker let queue_size = 128;
131*bb4ee6a4SAndroid Build Coastguard Worker
132*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(queue_size, None).unwrap();
133*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; 0x1000];
134*bb4ee6a4SAndroid Build Coastguard Worker let f = create_test_file(0x1000 * 2);
135*bb4ee6a4SAndroid Build Coastguard Worker
136*bb4ee6a4SAndroid Build Coastguard Worker // check that the whole file can be read and that the queues wrapping is handled by reading
137*bb4ee6a4SAndroid Build Coastguard Worker // double the quue depth of buffers.
138*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..queue_size * 2 {
139*bb4ee6a4SAndroid Build Coastguard Worker let index = i as u64;
140*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
141*bb4ee6a4SAndroid Build Coastguard Worker // safe to transmut from IoSlice to iovec.
142*bb4ee6a4SAndroid Build Coastguard Worker let io_vecs = unsafe {
143*bb4ee6a4SAndroid Build Coastguard Worker vec![IoSliceMut::new(&mut buf)]
144*bb4ee6a4SAndroid Build Coastguard Worker .into_iter()
145*bb4ee6a4SAndroid Build Coastguard Worker .map(|slice| std::mem::transmute::<IoSliceMut, libc::iovec>(slice))
146*bb4ee6a4SAndroid Build Coastguard Worker };
147*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
148*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the `wait` call waits until the kernel is done with `buf`.
149*bb4ee6a4SAndroid Build Coastguard Worker let (user_data_ret, res) = unsafe {
150*bb4ee6a4SAndroid Build Coastguard Worker uring
151*bb4ee6a4SAndroid Build Coastguard Worker .add_readv_iter(io_vecs, f.as_raw_fd(), Some((index % 2) * 0x1000), index)
152*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
153*bb4ee6a4SAndroid Build Coastguard Worker uring.wait().unwrap().next().unwrap()
154*bb4ee6a4SAndroid Build Coastguard Worker };
155*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data_ret, index);
156*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), buf.len() as u32);
157*bb4ee6a4SAndroid Build Coastguard Worker }
158*bb4ee6a4SAndroid Build Coastguard Worker }
159*bb4ee6a4SAndroid Build Coastguard Worker
160*bb4ee6a4SAndroid Build Coastguard Worker #[test]
readv_vec()161*bb4ee6a4SAndroid Build Coastguard Worker fn readv_vec() {
162*bb4ee6a4SAndroid Build Coastguard Worker let queue_size = 128;
163*bb4ee6a4SAndroid Build Coastguard Worker const BUF_SIZE: usize = 0x2000;
164*bb4ee6a4SAndroid Build Coastguard Worker
165*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(queue_size, None).unwrap();
166*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; BUF_SIZE];
167*bb4ee6a4SAndroid Build Coastguard Worker let mut buf2 = [0u8; BUF_SIZE];
168*bb4ee6a4SAndroid Build Coastguard Worker let mut buf3 = [0u8; BUF_SIZE];
169*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
170*bb4ee6a4SAndroid Build Coastguard Worker //safe to transmut from IoSlice to iovec.
171*bb4ee6a4SAndroid Build Coastguard Worker let io_vecs = unsafe {
172*bb4ee6a4SAndroid Build Coastguard Worker vec![
173*bb4ee6a4SAndroid Build Coastguard Worker IoSliceMut::new(&mut buf),
174*bb4ee6a4SAndroid Build Coastguard Worker IoSliceMut::new(&mut buf2),
175*bb4ee6a4SAndroid Build Coastguard Worker IoSliceMut::new(&mut buf3),
176*bb4ee6a4SAndroid Build Coastguard Worker ]
177*bb4ee6a4SAndroid Build Coastguard Worker .into_iter()
178*bb4ee6a4SAndroid Build Coastguard Worker .map(|slice| std::mem::transmute::<IoSliceMut, libc::iovec>(slice))
179*bb4ee6a4SAndroid Build Coastguard Worker .collect::<Vec<libc::iovec>>()
180*bb4ee6a4SAndroid Build Coastguard Worker };
181*bb4ee6a4SAndroid Build Coastguard Worker let total_len = io_vecs.iter().fold(0, |a, iovec| a + iovec.iov_len);
182*bb4ee6a4SAndroid Build Coastguard Worker let f = create_test_file(total_len as u64 * 2);
183*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
184*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the `wait` call waits until the kernel is done with `buf`.
185*bb4ee6a4SAndroid Build Coastguard Worker let (user_data_ret, res) = unsafe {
186*bb4ee6a4SAndroid Build Coastguard Worker uring
187*bb4ee6a4SAndroid Build Coastguard Worker .add_readv_iter(io_vecs.into_iter(), f.as_raw_fd(), Some(0), 55)
188*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
189*bb4ee6a4SAndroid Build Coastguard Worker uring.wait().unwrap().next().unwrap()
190*bb4ee6a4SAndroid Build Coastguard Worker };
191*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data_ret, 55);
192*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), total_len as u32);
193*bb4ee6a4SAndroid Build Coastguard Worker }
194*bb4ee6a4SAndroid Build Coastguard Worker
195*bb4ee6a4SAndroid Build Coastguard Worker #[test]
write_one_block()196*bb4ee6a4SAndroid Build Coastguard Worker fn write_one_block() {
197*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(16, None).unwrap();
198*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; 4096];
199*bb4ee6a4SAndroid Build Coastguard Worker let mut f = create_test_file(0);
200*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(&buf).unwrap();
201*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(&buf).unwrap();
202*bb4ee6a4SAndroid Build Coastguard Worker
203*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
204*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the `wait` call waits until the kernel is done mutating `buf`.
205*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
206*bb4ee6a4SAndroid Build Coastguard Worker add_one_write(
207*bb4ee6a4SAndroid Build Coastguard Worker &uring,
208*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr(),
209*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
210*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
211*bb4ee6a4SAndroid Build Coastguard Worker Some(0),
212*bb4ee6a4SAndroid Build Coastguard Worker 55,
213*bb4ee6a4SAndroid Build Coastguard Worker )
214*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
215*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, res) = uring.wait().unwrap().next().unwrap();
216*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, 55_u64);
217*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), buf.len() as u32);
218*bb4ee6a4SAndroid Build Coastguard Worker }
219*bb4ee6a4SAndroid Build Coastguard Worker }
220*bb4ee6a4SAndroid Build Coastguard Worker
221*bb4ee6a4SAndroid Build Coastguard Worker #[test]
write_one_submit_poll()222*bb4ee6a4SAndroid Build Coastguard Worker fn write_one_submit_poll() {
223*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(16, None).unwrap();
224*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; 4096];
225*bb4ee6a4SAndroid Build Coastguard Worker let mut f = create_test_file(0);
226*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(&buf).unwrap();
227*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(&buf).unwrap();
228*bb4ee6a4SAndroid Build Coastguard Worker
229*bb4ee6a4SAndroid Build Coastguard Worker let ctx: WaitContext<u64> = WaitContext::build_with(&[(&uring, 1)]).unwrap();
230*bb4ee6a4SAndroid Build Coastguard Worker {
231*bb4ee6a4SAndroid Build Coastguard Worker // Test that the uring context isn't readable before any events are complete.
232*bb4ee6a4SAndroid Build Coastguard Worker let events = ctx.wait_timeout(Duration::from_millis(1)).unwrap();
233*bb4ee6a4SAndroid Build Coastguard Worker assert!(events.iter().next().is_none());
234*bb4ee6a4SAndroid Build Coastguard Worker }
235*bb4ee6a4SAndroid Build Coastguard Worker
236*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
237*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the `wait` call waits until the kernel is done mutating `buf`.
238*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
239*bb4ee6a4SAndroid Build Coastguard Worker add_one_write(
240*bb4ee6a4SAndroid Build Coastguard Worker &uring,
241*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr(),
242*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
243*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
244*bb4ee6a4SAndroid Build Coastguard Worker Some(0),
245*bb4ee6a4SAndroid Build Coastguard Worker 55,
246*bb4ee6a4SAndroid Build Coastguard Worker )
247*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
248*bb4ee6a4SAndroid Build Coastguard Worker uring.submit().unwrap();
249*bb4ee6a4SAndroid Build Coastguard Worker // Poll for completion with epoll.
250*bb4ee6a4SAndroid Build Coastguard Worker let events = ctx.wait().unwrap();
251*bb4ee6a4SAndroid Build Coastguard Worker let event = events.iter().next().unwrap();
252*bb4ee6a4SAndroid Build Coastguard Worker assert!(event.is_readable);
253*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(event.token, 1);
254*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, res) = uring.wait().unwrap().next().unwrap();
255*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, 55_u64);
256*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), buf.len() as u32);
257*bb4ee6a4SAndroid Build Coastguard Worker }
258*bb4ee6a4SAndroid Build Coastguard Worker }
259*bb4ee6a4SAndroid Build Coastguard Worker
260*bb4ee6a4SAndroid Build Coastguard Worker #[test]
writev_vec()261*bb4ee6a4SAndroid Build Coastguard Worker fn writev_vec() {
262*bb4ee6a4SAndroid Build Coastguard Worker let queue_size = 128;
263*bb4ee6a4SAndroid Build Coastguard Worker const BUF_SIZE: usize = 0x2000;
264*bb4ee6a4SAndroid Build Coastguard Worker const OFFSET: u64 = 0x2000;
265*bb4ee6a4SAndroid Build Coastguard Worker
266*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(queue_size, None).unwrap();
267*bb4ee6a4SAndroid Build Coastguard Worker let buf = [0xaau8; BUF_SIZE];
268*bb4ee6a4SAndroid Build Coastguard Worker let buf2 = [0xffu8; BUF_SIZE];
269*bb4ee6a4SAndroid Build Coastguard Worker let buf3 = [0x55u8; BUF_SIZE];
270*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
271*bb4ee6a4SAndroid Build Coastguard Worker //safe to transmut from IoSlice to iovec.
272*bb4ee6a4SAndroid Build Coastguard Worker let io_vecs = unsafe {
273*bb4ee6a4SAndroid Build Coastguard Worker vec![IoSlice::new(&buf), IoSlice::new(&buf2), IoSlice::new(&buf3)]
274*bb4ee6a4SAndroid Build Coastguard Worker .into_iter()
275*bb4ee6a4SAndroid Build Coastguard Worker .map(|slice| std::mem::transmute::<IoSlice, libc::iovec>(slice))
276*bb4ee6a4SAndroid Build Coastguard Worker .collect::<Vec<libc::iovec>>()
277*bb4ee6a4SAndroid Build Coastguard Worker };
278*bb4ee6a4SAndroid Build Coastguard Worker let total_len = io_vecs.iter().fold(0, |a, iovec| a + iovec.iov_len);
279*bb4ee6a4SAndroid Build Coastguard Worker let mut f = create_test_file(total_len as u64 * 2);
280*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
281*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the `wait` call waits until the kernel is done with `buf`.
282*bb4ee6a4SAndroid Build Coastguard Worker let (user_data_ret, res) = unsafe {
283*bb4ee6a4SAndroid Build Coastguard Worker uring
284*bb4ee6a4SAndroid Build Coastguard Worker .add_writev_iter(io_vecs.into_iter(), f.as_raw_fd(), Some(OFFSET), 55)
285*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
286*bb4ee6a4SAndroid Build Coastguard Worker uring.wait().unwrap().next().unwrap()
287*bb4ee6a4SAndroid Build Coastguard Worker };
288*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data_ret, 55);
289*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), total_len as u32);
290*bb4ee6a4SAndroid Build Coastguard Worker
291*bb4ee6a4SAndroid Build Coastguard Worker let mut read_back = [0u8; BUF_SIZE];
292*bb4ee6a4SAndroid Build Coastguard Worker f.seek(SeekFrom::Start(OFFSET)).unwrap();
293*bb4ee6a4SAndroid Build Coastguard Worker f.read_exact(&mut read_back).unwrap();
294*bb4ee6a4SAndroid Build Coastguard Worker assert!(!read_back.iter().any(|&b| b != 0xaa));
295*bb4ee6a4SAndroid Build Coastguard Worker f.read_exact(&mut read_back).unwrap();
296*bb4ee6a4SAndroid Build Coastguard Worker assert!(!read_back.iter().any(|&b| b != 0xff));
297*bb4ee6a4SAndroid Build Coastguard Worker f.read_exact(&mut read_back).unwrap();
298*bb4ee6a4SAndroid Build Coastguard Worker assert!(!read_back.iter().any(|&b| b != 0x55));
299*bb4ee6a4SAndroid Build Coastguard Worker }
300*bb4ee6a4SAndroid Build Coastguard Worker
301*bb4ee6a4SAndroid Build Coastguard Worker #[test]
fallocate_fsync()302*bb4ee6a4SAndroid Build Coastguard Worker fn fallocate_fsync() {
303*bb4ee6a4SAndroid Build Coastguard Worker let tempdir = TempDir::new().unwrap();
304*bb4ee6a4SAndroid Build Coastguard Worker let file_path = append_file_name(tempdir.path(), "test");
305*bb4ee6a4SAndroid Build Coastguard Worker
306*bb4ee6a4SAndroid Build Coastguard Worker {
307*bb4ee6a4SAndroid Build Coastguard Worker let buf = [0u8; 4096];
308*bb4ee6a4SAndroid Build Coastguard Worker let mut f = OpenOptions::new()
309*bb4ee6a4SAndroid Build Coastguard Worker .read(true)
310*bb4ee6a4SAndroid Build Coastguard Worker .write(true)
311*bb4ee6a4SAndroid Build Coastguard Worker .create_new(true)
312*bb4ee6a4SAndroid Build Coastguard Worker .open(&file_path)
313*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
314*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(&buf).unwrap();
315*bb4ee6a4SAndroid Build Coastguard Worker }
316*bb4ee6a4SAndroid Build Coastguard Worker
317*bb4ee6a4SAndroid Build Coastguard Worker let init_size = std::fs::metadata(&file_path).unwrap().len() as usize;
318*bb4ee6a4SAndroid Build Coastguard Worker let set_size = init_size + 1024 * 1024 * 50;
319*bb4ee6a4SAndroid Build Coastguard Worker let f = OpenOptions::new()
320*bb4ee6a4SAndroid Build Coastguard Worker .read(true)
321*bb4ee6a4SAndroid Build Coastguard Worker .write(true)
322*bb4ee6a4SAndroid Build Coastguard Worker .create(true)
323*bb4ee6a4SAndroid Build Coastguard Worker .truncate(false)
324*bb4ee6a4SAndroid Build Coastguard Worker .open(&file_path)
325*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
326*bb4ee6a4SAndroid Build Coastguard Worker
327*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(16, None).unwrap();
328*bb4ee6a4SAndroid Build Coastguard Worker uring
329*bb4ee6a4SAndroid Build Coastguard Worker .add_fallocate(f.as_raw_fd(), 0, set_size as u64, 0, 66)
330*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
331*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, res) = uring.wait().unwrap().next().unwrap();
332*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, 66_u64);
333*bb4ee6a4SAndroid Build Coastguard Worker match res {
334*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
335*bb4ee6a4SAndroid Build Coastguard Worker if e.kind() == std::io::ErrorKind::InvalidInput {
336*bb4ee6a4SAndroid Build Coastguard Worker // skip on kernels that don't support fallocate.
337*bb4ee6a4SAndroid Build Coastguard Worker return;
338*bb4ee6a4SAndroid Build Coastguard Worker }
339*bb4ee6a4SAndroid Build Coastguard Worker panic!("Unexpected fallocate error: {}", e);
340*bb4ee6a4SAndroid Build Coastguard Worker }
341*bb4ee6a4SAndroid Build Coastguard Worker Ok(val) => assert_eq!(val, 0_u32),
342*bb4ee6a4SAndroid Build Coastguard Worker }
343*bb4ee6a4SAndroid Build Coastguard Worker
344*bb4ee6a4SAndroid Build Coastguard Worker // Add a few writes and then fsync
345*bb4ee6a4SAndroid Build Coastguard Worker let buf = [0u8; 4096];
346*bb4ee6a4SAndroid Build Coastguard Worker let mut pending = std::collections::BTreeSet::new();
347*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
348*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
349*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
350*bb4ee6a4SAndroid Build Coastguard Worker add_one_write(&uring, buf.as_ptr(), buf.len(), f.as_raw_fd(), Some(0), 67).unwrap();
351*bb4ee6a4SAndroid Build Coastguard Worker pending.insert(67u64);
352*bb4ee6a4SAndroid Build Coastguard Worker add_one_write(
353*bb4ee6a4SAndroid Build Coastguard Worker &uring,
354*bb4ee6a4SAndroid Build Coastguard Worker buf.as_ptr(),
355*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
356*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
357*bb4ee6a4SAndroid Build Coastguard Worker Some(4096),
358*bb4ee6a4SAndroid Build Coastguard Worker 68,
359*bb4ee6a4SAndroid Build Coastguard Worker )
360*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
361*bb4ee6a4SAndroid Build Coastguard Worker pending.insert(68);
362*bb4ee6a4SAndroid Build Coastguard Worker add_one_write(
363*bb4ee6a4SAndroid Build Coastguard Worker &uring,
364*bb4ee6a4SAndroid Build Coastguard Worker buf.as_ptr(),
365*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
366*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
367*bb4ee6a4SAndroid Build Coastguard Worker Some(8192),
368*bb4ee6a4SAndroid Build Coastguard Worker 69,
369*bb4ee6a4SAndroid Build Coastguard Worker )
370*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
371*bb4ee6a4SAndroid Build Coastguard Worker pending.insert(69);
372*bb4ee6a4SAndroid Build Coastguard Worker }
373*bb4ee6a4SAndroid Build Coastguard Worker uring.add_fsync(f.as_raw_fd(), 70).unwrap();
374*bb4ee6a4SAndroid Build Coastguard Worker pending.insert(70);
375*bb4ee6a4SAndroid Build Coastguard Worker
376*bb4ee6a4SAndroid Build Coastguard Worker let mut wait_calls = 0;
377*bb4ee6a4SAndroid Build Coastguard Worker
378*bb4ee6a4SAndroid Build Coastguard Worker while !pending.is_empty() && wait_calls < 5 {
379*bb4ee6a4SAndroid Build Coastguard Worker let events = uring.wait().unwrap();
380*bb4ee6a4SAndroid Build Coastguard Worker for (user_data, res) in events {
381*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_ok());
382*bb4ee6a4SAndroid Build Coastguard Worker assert!(pending.contains(&user_data));
383*bb4ee6a4SAndroid Build Coastguard Worker pending.remove(&user_data);
384*bb4ee6a4SAndroid Build Coastguard Worker }
385*bb4ee6a4SAndroid Build Coastguard Worker wait_calls += 1;
386*bb4ee6a4SAndroid Build Coastguard Worker }
387*bb4ee6a4SAndroid Build Coastguard Worker assert!(pending.is_empty());
388*bb4ee6a4SAndroid Build Coastguard Worker
389*bb4ee6a4SAndroid Build Coastguard Worker uring
390*bb4ee6a4SAndroid Build Coastguard Worker .add_fallocate(
391*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
392*bb4ee6a4SAndroid Build Coastguard Worker init_size as u64,
393*bb4ee6a4SAndroid Build Coastguard Worker (set_size - init_size) as u64,
394*bb4ee6a4SAndroid Build Coastguard Worker (libc::FALLOC_FL_PUNCH_HOLE | libc::FALLOC_FL_KEEP_SIZE) as u32,
395*bb4ee6a4SAndroid Build Coastguard Worker 68,
396*bb4ee6a4SAndroid Build Coastguard Worker )
397*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
398*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, res) = uring.wait().unwrap().next().unwrap();
399*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, 68_u64);
400*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), 0_u32);
401*bb4ee6a4SAndroid Build Coastguard Worker
402*bb4ee6a4SAndroid Build Coastguard Worker drop(f); // Close to ensure directory entires for metadata are updated.
403*bb4ee6a4SAndroid Build Coastguard Worker
404*bb4ee6a4SAndroid Build Coastguard Worker let new_size = std::fs::metadata(&file_path).unwrap().len() as usize;
405*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(new_size, set_size);
406*bb4ee6a4SAndroid Build Coastguard Worker }
407*bb4ee6a4SAndroid Build Coastguard Worker
408*bb4ee6a4SAndroid Build Coastguard Worker #[test]
dev_zero_readable()409*bb4ee6a4SAndroid Build Coastguard Worker fn dev_zero_readable() {
410*bb4ee6a4SAndroid Build Coastguard Worker let f = File::open(Path::new("/dev/zero")).unwrap();
411*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(16, None).unwrap();
412*bb4ee6a4SAndroid Build Coastguard Worker uring
413*bb4ee6a4SAndroid Build Coastguard Worker .add_poll_fd(f.as_raw_fd(), EventType::Read, 454)
414*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
415*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, res) = uring.wait().unwrap().next().unwrap();
416*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, 454_u64);
417*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), 1_u32);
418*bb4ee6a4SAndroid Build Coastguard Worker }
419*bb4ee6a4SAndroid Build Coastguard Worker
420*bb4ee6a4SAndroid Build Coastguard Worker #[test]
queue_many_ebusy_retry()421*bb4ee6a4SAndroid Build Coastguard Worker fn queue_many_ebusy_retry() {
422*bb4ee6a4SAndroid Build Coastguard Worker let num_entries = 16;
423*bb4ee6a4SAndroid Build Coastguard Worker let f = File::open(Path::new("/dev/zero")).unwrap();
424*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(num_entries, None).unwrap();
425*bb4ee6a4SAndroid Build Coastguard Worker // Fill the sumbit ring.
426*bb4ee6a4SAndroid Build Coastguard Worker for sqe_batch in 0..3 {
427*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..num_entries {
428*bb4ee6a4SAndroid Build Coastguard Worker uring
429*bb4ee6a4SAndroid Build Coastguard Worker .add_poll_fd(
430*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
431*bb4ee6a4SAndroid Build Coastguard Worker EventType::Read,
432*bb4ee6a4SAndroid Build Coastguard Worker (sqe_batch * num_entries + i) as u64,
433*bb4ee6a4SAndroid Build Coastguard Worker )
434*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
435*bb4ee6a4SAndroid Build Coastguard Worker }
436*bb4ee6a4SAndroid Build Coastguard Worker uring.submit().unwrap();
437*bb4ee6a4SAndroid Build Coastguard Worker }
438*bb4ee6a4SAndroid Build Coastguard Worker // Adding more than the number of cqes will cause the uring to return ebusy, make sure that
439*bb4ee6a4SAndroid Build Coastguard Worker // is handled cleanly and wait still returns the completed entries.
440*bb4ee6a4SAndroid Build Coastguard Worker uring
441*bb4ee6a4SAndroid Build Coastguard Worker .add_poll_fd(f.as_raw_fd(), EventType::Read, (num_entries * 3) as u64)
442*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
443*bb4ee6a4SAndroid Build Coastguard Worker // The first wait call should return the cques that are already filled.
444*bb4ee6a4SAndroid Build Coastguard Worker {
445*bb4ee6a4SAndroid Build Coastguard Worker let mut results = uring.wait().unwrap();
446*bb4ee6a4SAndroid Build Coastguard Worker for _i in 0..num_entries * 2 {
447*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(results.next().unwrap().1.unwrap(), 1_u32);
448*bb4ee6a4SAndroid Build Coastguard Worker }
449*bb4ee6a4SAndroid Build Coastguard Worker assert!(results.next().is_none());
450*bb4ee6a4SAndroid Build Coastguard Worker }
451*bb4ee6a4SAndroid Build Coastguard Worker // The second will finish submitting any more sqes and return the rest.
452*bb4ee6a4SAndroid Build Coastguard Worker let mut results = uring.wait().unwrap();
453*bb4ee6a4SAndroid Build Coastguard Worker for _i in 0..num_entries + 1 {
454*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(results.next().unwrap().1.unwrap(), 1_u32);
455*bb4ee6a4SAndroid Build Coastguard Worker }
456*bb4ee6a4SAndroid Build Coastguard Worker assert!(results.next().is_none());
457*bb4ee6a4SAndroid Build Coastguard Worker }
458*bb4ee6a4SAndroid Build Coastguard Worker
459*bb4ee6a4SAndroid Build Coastguard Worker #[test]
wake_with_nop()460*bb4ee6a4SAndroid Build Coastguard Worker fn wake_with_nop() {
461*bb4ee6a4SAndroid Build Coastguard Worker const PIPE_READ: UserData = 0;
462*bb4ee6a4SAndroid Build Coastguard Worker const NOP: UserData = 1;
463*bb4ee6a4SAndroid Build Coastguard Worker const BUF_DATA: [u8; 16] = [0xf4; 16];
464*bb4ee6a4SAndroid Build Coastguard Worker
465*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(4, None).map(Arc::new).unwrap();
466*bb4ee6a4SAndroid Build Coastguard Worker let (pipe_out, mut pipe_in) = pipe().unwrap();
467*bb4ee6a4SAndroid Build Coastguard Worker let (tx, rx) = channel();
468*bb4ee6a4SAndroid Build Coastguard Worker
469*bb4ee6a4SAndroid Build Coastguard Worker let uring2 = uring.clone();
470*bb4ee6a4SAndroid Build Coastguard Worker let wait_thread = thread::spawn(move || {
471*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; BUF_DATA.len()];
472*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
473*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
474*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
475*bb4ee6a4SAndroid Build Coastguard Worker add_one_read(
476*bb4ee6a4SAndroid Build Coastguard Worker &uring2,
477*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr(),
478*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
479*bb4ee6a4SAndroid Build Coastguard Worker pipe_out.as_raw_fd(),
480*bb4ee6a4SAndroid Build Coastguard Worker Some(0),
481*bb4ee6a4SAndroid Build Coastguard Worker 0,
482*bb4ee6a4SAndroid Build Coastguard Worker )
483*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
484*bb4ee6a4SAndroid Build Coastguard Worker }
485*bb4ee6a4SAndroid Build Coastguard Worker
486*bb4ee6a4SAndroid Build Coastguard Worker // This is still a bit racy as the other thread may end up adding the NOP before we make
487*bb4ee6a4SAndroid Build Coastguard Worker // the syscall but I'm not aware of a mechanism that will notify the other thread
488*bb4ee6a4SAndroid Build Coastguard Worker // exactly when we make the syscall.
489*bb4ee6a4SAndroid Build Coastguard Worker tx.send(()).unwrap();
490*bb4ee6a4SAndroid Build Coastguard Worker let mut events = uring2.wait().unwrap();
491*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, result) = events.next().unwrap();
492*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, NOP);
493*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result.unwrap(), 0);
494*bb4ee6a4SAndroid Build Coastguard Worker
495*bb4ee6a4SAndroid Build Coastguard Worker tx.send(()).unwrap();
496*bb4ee6a4SAndroid Build Coastguard Worker let mut events = uring2.wait().unwrap();
497*bb4ee6a4SAndroid Build Coastguard Worker let (user_data, result) = events.next().unwrap();
498*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(user_data, PIPE_READ);
499*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result.unwrap(), buf.len() as u32);
500*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&buf, &BUF_DATA);
501*bb4ee6a4SAndroid Build Coastguard Worker });
502*bb4ee6a4SAndroid Build Coastguard Worker
503*bb4ee6a4SAndroid Build Coastguard Worker // Wait until the other thread is about to make the syscall.
504*bb4ee6a4SAndroid Build Coastguard Worker rx.recv_timeout(Duration::from_secs(10)).unwrap();
505*bb4ee6a4SAndroid Build Coastguard Worker
506*bb4ee6a4SAndroid Build Coastguard Worker // Now add a NOP operation. This should wake up the other thread even though it cannot yet
507*bb4ee6a4SAndroid Build Coastguard Worker // read from the pipe.
508*bb4ee6a4SAndroid Build Coastguard Worker uring.add_nop(NOP).unwrap();
509*bb4ee6a4SAndroid Build Coastguard Worker uring.submit().unwrap();
510*bb4ee6a4SAndroid Build Coastguard Worker
511*bb4ee6a4SAndroid Build Coastguard Worker // Wait for the other thread to process the NOP result.
512*bb4ee6a4SAndroid Build Coastguard Worker rx.recv_timeout(Duration::from_secs(10)).unwrap();
513*bb4ee6a4SAndroid Build Coastguard Worker
514*bb4ee6a4SAndroid Build Coastguard Worker // Now write to the pipe to finish the uring read.
515*bb4ee6a4SAndroid Build Coastguard Worker pipe_in.write_all(&BUF_DATA).unwrap();
516*bb4ee6a4SAndroid Build Coastguard Worker
517*bb4ee6a4SAndroid Build Coastguard Worker wait_thread.join().unwrap();
518*bb4ee6a4SAndroid Build Coastguard Worker }
519*bb4ee6a4SAndroid Build Coastguard Worker
520*bb4ee6a4SAndroid Build Coastguard Worker #[test]
complete_from_any_thread()521*bb4ee6a4SAndroid Build Coastguard Worker fn complete_from_any_thread() {
522*bb4ee6a4SAndroid Build Coastguard Worker let num_entries = 16;
523*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(num_entries, None).map(Arc::new).unwrap();
524*bb4ee6a4SAndroid Build Coastguard Worker
525*bb4ee6a4SAndroid Build Coastguard Worker // Fill the sumbit ring.
526*bb4ee6a4SAndroid Build Coastguard Worker for sqe_batch in 0..3 {
527*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..num_entries {
528*bb4ee6a4SAndroid Build Coastguard Worker uring.add_nop((sqe_batch * num_entries + i) as u64).unwrap();
529*bb4ee6a4SAndroid Build Coastguard Worker }
530*bb4ee6a4SAndroid Build Coastguard Worker uring.submit().unwrap();
531*bb4ee6a4SAndroid Build Coastguard Worker }
532*bb4ee6a4SAndroid Build Coastguard Worker
533*bb4ee6a4SAndroid Build Coastguard Worker // Spawn a bunch of threads that pull cqes out of the uring and make sure none of them see a
534*bb4ee6a4SAndroid Build Coastguard Worker // duplicate.
535*bb4ee6a4SAndroid Build Coastguard Worker const NUM_THREADS: usize = 7;
536*bb4ee6a4SAndroid Build Coastguard Worker let completed = Arc::new(Mutex::new(BTreeSet::new()));
537*bb4ee6a4SAndroid Build Coastguard Worker let cv = Arc::new(Condvar::new());
538*bb4ee6a4SAndroid Build Coastguard Worker let barrier = Arc::new(Barrier::new(NUM_THREADS));
539*bb4ee6a4SAndroid Build Coastguard Worker
540*bb4ee6a4SAndroid Build Coastguard Worker let mut threads = Vec::with_capacity(NUM_THREADS);
541*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..NUM_THREADS {
542*bb4ee6a4SAndroid Build Coastguard Worker let uring = uring.clone();
543*bb4ee6a4SAndroid Build Coastguard Worker let completed = completed.clone();
544*bb4ee6a4SAndroid Build Coastguard Worker let barrier = barrier.clone();
545*bb4ee6a4SAndroid Build Coastguard Worker let cv = cv.clone();
546*bb4ee6a4SAndroid Build Coastguard Worker threads.push(thread::spawn(move || {
547*bb4ee6a4SAndroid Build Coastguard Worker barrier.wait();
548*bb4ee6a4SAndroid Build Coastguard Worker
549*bb4ee6a4SAndroid Build Coastguard Worker 'wait: while completed.lock().len() < num_entries * 3 {
550*bb4ee6a4SAndroid Build Coastguard Worker for (user_data, result) in uring.wait().unwrap() {
551*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result.unwrap(), 0);
552*bb4ee6a4SAndroid Build Coastguard Worker
553*bb4ee6a4SAndroid Build Coastguard Worker let mut completed = completed.lock();
554*bb4ee6a4SAndroid Build Coastguard Worker assert!(completed.insert(user_data));
555*bb4ee6a4SAndroid Build Coastguard Worker if completed.len() >= num_entries * 3 {
556*bb4ee6a4SAndroid Build Coastguard Worker break 'wait;
557*bb4ee6a4SAndroid Build Coastguard Worker }
558*bb4ee6a4SAndroid Build Coastguard Worker }
559*bb4ee6a4SAndroid Build Coastguard Worker }
560*bb4ee6a4SAndroid Build Coastguard Worker
561*bb4ee6a4SAndroid Build Coastguard Worker cv.notify_one();
562*bb4ee6a4SAndroid Build Coastguard Worker }));
563*bb4ee6a4SAndroid Build Coastguard Worker }
564*bb4ee6a4SAndroid Build Coastguard Worker
565*bb4ee6a4SAndroid Build Coastguard Worker // Wait until all the operations have completed.
566*bb4ee6a4SAndroid Build Coastguard Worker let mut c = completed.lock();
567*bb4ee6a4SAndroid Build Coastguard Worker while c.len() < num_entries * 3 {
568*bb4ee6a4SAndroid Build Coastguard Worker c = cv.wait(c);
569*bb4ee6a4SAndroid Build Coastguard Worker }
570*bb4ee6a4SAndroid Build Coastguard Worker mem::drop(c);
571*bb4ee6a4SAndroid Build Coastguard Worker
572*bb4ee6a4SAndroid Build Coastguard Worker // Let the OS clean up the still-waiting threads after the test run.
573*bb4ee6a4SAndroid Build Coastguard Worker }
574*bb4ee6a4SAndroid Build Coastguard Worker
575*bb4ee6a4SAndroid Build Coastguard Worker #[test]
submit_from_any_thread()576*bb4ee6a4SAndroid Build Coastguard Worker fn submit_from_any_thread() {
577*bb4ee6a4SAndroid Build Coastguard Worker const NUM_THREADS: usize = 7;
578*bb4ee6a4SAndroid Build Coastguard Worker const ITERATIONS: usize = 113;
579*bb4ee6a4SAndroid Build Coastguard Worker const NUM_ENTRIES: usize = 16;
580*bb4ee6a4SAndroid Build Coastguard Worker
581*bb4ee6a4SAndroid Build Coastguard Worker fn wait_for_completion_thread(in_flight: &Mutex<isize>, cv: &Condvar) {
582*bb4ee6a4SAndroid Build Coastguard Worker let mut in_flight = in_flight.lock();
583*bb4ee6a4SAndroid Build Coastguard Worker while *in_flight > NUM_ENTRIES as isize {
584*bb4ee6a4SAndroid Build Coastguard Worker in_flight = cv.wait(in_flight);
585*bb4ee6a4SAndroid Build Coastguard Worker }
586*bb4ee6a4SAndroid Build Coastguard Worker }
587*bb4ee6a4SAndroid Build Coastguard Worker
588*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(NUM_ENTRIES, None).map(Arc::new).unwrap();
589*bb4ee6a4SAndroid Build Coastguard Worker let in_flight = Arc::new(Mutex::new(0));
590*bb4ee6a4SAndroid Build Coastguard Worker let cv = Arc::new(Condvar::new());
591*bb4ee6a4SAndroid Build Coastguard Worker
592*bb4ee6a4SAndroid Build Coastguard Worker let mut threads = Vec::with_capacity(NUM_THREADS);
593*bb4ee6a4SAndroid Build Coastguard Worker for idx in 0..NUM_THREADS {
594*bb4ee6a4SAndroid Build Coastguard Worker let uring = uring.clone();
595*bb4ee6a4SAndroid Build Coastguard Worker let in_flight = in_flight.clone();
596*bb4ee6a4SAndroid Build Coastguard Worker let cv = cv.clone();
597*bb4ee6a4SAndroid Build Coastguard Worker threads.push(thread::spawn(move || {
598*bb4ee6a4SAndroid Build Coastguard Worker for iter in 0..ITERATIONS {
599*bb4ee6a4SAndroid Build Coastguard Worker loop {
600*bb4ee6a4SAndroid Build Coastguard Worker match uring.add_nop(((idx * NUM_THREADS) + iter) as UserData) {
601*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => *in_flight.lock() += 1,
602*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::NoSpace) => {
603*bb4ee6a4SAndroid Build Coastguard Worker wait_for_completion_thread(&in_flight, &cv);
604*bb4ee6a4SAndroid Build Coastguard Worker continue;
605*bb4ee6a4SAndroid Build Coastguard Worker }
606*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => panic!("Failed to add nop: {}", e),
607*bb4ee6a4SAndroid Build Coastguard Worker }
608*bb4ee6a4SAndroid Build Coastguard Worker
609*bb4ee6a4SAndroid Build Coastguard Worker // We don't need to wait for the completion queue if the submit fails with
610*bb4ee6a4SAndroid Build Coastguard Worker // EBUSY because we already added the operation to the submit queue. It will
611*bb4ee6a4SAndroid Build Coastguard Worker // get added eventually.
612*bb4ee6a4SAndroid Build Coastguard Worker match uring.submit() {
613*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => break,
614*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::RingEnter(libc::EBUSY)) => break,
615*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => panic!("Failed to submit ops: {}", e),
616*bb4ee6a4SAndroid Build Coastguard Worker }
617*bb4ee6a4SAndroid Build Coastguard Worker }
618*bb4ee6a4SAndroid Build Coastguard Worker }
619*bb4ee6a4SAndroid Build Coastguard Worker }));
620*bb4ee6a4SAndroid Build Coastguard Worker }
621*bb4ee6a4SAndroid Build Coastguard Worker
622*bb4ee6a4SAndroid Build Coastguard Worker let mut completed = 0;
623*bb4ee6a4SAndroid Build Coastguard Worker while completed < NUM_THREADS * ITERATIONS {
624*bb4ee6a4SAndroid Build Coastguard Worker for (_, res) in uring.wait().unwrap() {
625*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), 0);
626*bb4ee6a4SAndroid Build Coastguard Worker completed += 1;
627*bb4ee6a4SAndroid Build Coastguard Worker
628*bb4ee6a4SAndroid Build Coastguard Worker let mut in_flight = in_flight.lock();
629*bb4ee6a4SAndroid Build Coastguard Worker *in_flight -= 1;
630*bb4ee6a4SAndroid Build Coastguard Worker let notify_submitters = *in_flight <= NUM_ENTRIES as isize;
631*bb4ee6a4SAndroid Build Coastguard Worker mem::drop(in_flight);
632*bb4ee6a4SAndroid Build Coastguard Worker
633*bb4ee6a4SAndroid Build Coastguard Worker if notify_submitters {
634*bb4ee6a4SAndroid Build Coastguard Worker cv.notify_all();
635*bb4ee6a4SAndroid Build Coastguard Worker }
636*bb4ee6a4SAndroid Build Coastguard Worker
637*bb4ee6a4SAndroid Build Coastguard Worker if completed >= NUM_THREADS * ITERATIONS {
638*bb4ee6a4SAndroid Build Coastguard Worker break;
639*bb4ee6a4SAndroid Build Coastguard Worker }
640*bb4ee6a4SAndroid Build Coastguard Worker }
641*bb4ee6a4SAndroid Build Coastguard Worker }
642*bb4ee6a4SAndroid Build Coastguard Worker
643*bb4ee6a4SAndroid Build Coastguard Worker for t in threads {
644*bb4ee6a4SAndroid Build Coastguard Worker t.join().unwrap();
645*bb4ee6a4SAndroid Build Coastguard Worker }
646*bb4ee6a4SAndroid Build Coastguard Worker
647*bb4ee6a4SAndroid Build Coastguard Worker // Make sure we didn't submit more entries than expected.
648*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*in_flight.lock(), 0);
649*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(uring.submit_ring.lock().added, 0);
650*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(uring.complete_ring.num_ready(), 0);
651*bb4ee6a4SAndroid Build Coastguard Worker }
652*bb4ee6a4SAndroid Build Coastguard Worker
653*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/183722981): Fix and re-enable test
654*bb4ee6a4SAndroid Build Coastguard Worker #[test]
655*bb4ee6a4SAndroid Build Coastguard Worker #[ignore]
multi_thread_submit_and_complete()656*bb4ee6a4SAndroid Build Coastguard Worker fn multi_thread_submit_and_complete() {
657*bb4ee6a4SAndroid Build Coastguard Worker const NUM_SUBMITTERS: usize = 7;
658*bb4ee6a4SAndroid Build Coastguard Worker const NUM_COMPLETERS: usize = 3;
659*bb4ee6a4SAndroid Build Coastguard Worker const ITERATIONS: usize = 113;
660*bb4ee6a4SAndroid Build Coastguard Worker const NUM_ENTRIES: usize = 16;
661*bb4ee6a4SAndroid Build Coastguard Worker
662*bb4ee6a4SAndroid Build Coastguard Worker fn wait_for_completion_thread(in_flight: &Mutex<isize>, cv: &Condvar) {
663*bb4ee6a4SAndroid Build Coastguard Worker let mut in_flight = in_flight.lock();
664*bb4ee6a4SAndroid Build Coastguard Worker while *in_flight > NUM_ENTRIES as isize {
665*bb4ee6a4SAndroid Build Coastguard Worker in_flight = cv.wait(in_flight);
666*bb4ee6a4SAndroid Build Coastguard Worker }
667*bb4ee6a4SAndroid Build Coastguard Worker }
668*bb4ee6a4SAndroid Build Coastguard Worker
669*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(NUM_ENTRIES, None).map(Arc::new).unwrap();
670*bb4ee6a4SAndroid Build Coastguard Worker let in_flight = Arc::new(Mutex::new(0));
671*bb4ee6a4SAndroid Build Coastguard Worker let cv = Arc::new(Condvar::new());
672*bb4ee6a4SAndroid Build Coastguard Worker
673*bb4ee6a4SAndroid Build Coastguard Worker let mut threads = Vec::with_capacity(NUM_SUBMITTERS + NUM_COMPLETERS);
674*bb4ee6a4SAndroid Build Coastguard Worker for idx in 0..NUM_SUBMITTERS {
675*bb4ee6a4SAndroid Build Coastguard Worker let uring = uring.clone();
676*bb4ee6a4SAndroid Build Coastguard Worker let in_flight = in_flight.clone();
677*bb4ee6a4SAndroid Build Coastguard Worker let cv = cv.clone();
678*bb4ee6a4SAndroid Build Coastguard Worker threads.push(thread::spawn(move || {
679*bb4ee6a4SAndroid Build Coastguard Worker for iter in 0..ITERATIONS {
680*bb4ee6a4SAndroid Build Coastguard Worker loop {
681*bb4ee6a4SAndroid Build Coastguard Worker match uring.add_nop(((idx * NUM_SUBMITTERS) + iter) as UserData) {
682*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => *in_flight.lock() += 1,
683*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::NoSpace) => {
684*bb4ee6a4SAndroid Build Coastguard Worker wait_for_completion_thread(&in_flight, &cv);
685*bb4ee6a4SAndroid Build Coastguard Worker continue;
686*bb4ee6a4SAndroid Build Coastguard Worker }
687*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => panic!("Failed to add nop: {}", e),
688*bb4ee6a4SAndroid Build Coastguard Worker }
689*bb4ee6a4SAndroid Build Coastguard Worker
690*bb4ee6a4SAndroid Build Coastguard Worker // We don't need to wait for the completion queue if the submit fails with
691*bb4ee6a4SAndroid Build Coastguard Worker // EBUSY because we already added the operation to the submit queue. It will
692*bb4ee6a4SAndroid Build Coastguard Worker // get added eventually.
693*bb4ee6a4SAndroid Build Coastguard Worker match uring.submit() {
694*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => break,
695*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::RingEnter(libc::EBUSY)) => break,
696*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => panic!("Failed to submit ops: {}", e),
697*bb4ee6a4SAndroid Build Coastguard Worker }
698*bb4ee6a4SAndroid Build Coastguard Worker }
699*bb4ee6a4SAndroid Build Coastguard Worker }
700*bb4ee6a4SAndroid Build Coastguard Worker }));
701*bb4ee6a4SAndroid Build Coastguard Worker }
702*bb4ee6a4SAndroid Build Coastguard Worker
703*bb4ee6a4SAndroid Build Coastguard Worker let completed = Arc::new(AtomicUsize::new(0));
704*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..NUM_COMPLETERS {
705*bb4ee6a4SAndroid Build Coastguard Worker let uring = uring.clone();
706*bb4ee6a4SAndroid Build Coastguard Worker let in_flight = in_flight.clone();
707*bb4ee6a4SAndroid Build Coastguard Worker let cv = cv.clone();
708*bb4ee6a4SAndroid Build Coastguard Worker let completed = completed.clone();
709*bb4ee6a4SAndroid Build Coastguard Worker threads.push(thread::spawn(move || {
710*bb4ee6a4SAndroid Build Coastguard Worker while completed.load(Ordering::Relaxed) < NUM_SUBMITTERS * ITERATIONS {
711*bb4ee6a4SAndroid Build Coastguard Worker for (_, res) in uring.wait().unwrap() {
712*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(res.unwrap(), 0);
713*bb4ee6a4SAndroid Build Coastguard Worker completed.fetch_add(1, Ordering::Relaxed);
714*bb4ee6a4SAndroid Build Coastguard Worker
715*bb4ee6a4SAndroid Build Coastguard Worker let mut in_flight = in_flight.lock();
716*bb4ee6a4SAndroid Build Coastguard Worker *in_flight -= 1;
717*bb4ee6a4SAndroid Build Coastguard Worker let notify_submitters = *in_flight <= NUM_ENTRIES as isize;
718*bb4ee6a4SAndroid Build Coastguard Worker mem::drop(in_flight);
719*bb4ee6a4SAndroid Build Coastguard Worker
720*bb4ee6a4SAndroid Build Coastguard Worker if notify_submitters {
721*bb4ee6a4SAndroid Build Coastguard Worker cv.notify_all();
722*bb4ee6a4SAndroid Build Coastguard Worker }
723*bb4ee6a4SAndroid Build Coastguard Worker
724*bb4ee6a4SAndroid Build Coastguard Worker if completed.load(Ordering::Relaxed) >= NUM_SUBMITTERS * ITERATIONS {
725*bb4ee6a4SAndroid Build Coastguard Worker break;
726*bb4ee6a4SAndroid Build Coastguard Worker }
727*bb4ee6a4SAndroid Build Coastguard Worker }
728*bb4ee6a4SAndroid Build Coastguard Worker }
729*bb4ee6a4SAndroid Build Coastguard Worker }));
730*bb4ee6a4SAndroid Build Coastguard Worker }
731*bb4ee6a4SAndroid Build Coastguard Worker
732*bb4ee6a4SAndroid Build Coastguard Worker for t in threads.drain(..NUM_SUBMITTERS) {
733*bb4ee6a4SAndroid Build Coastguard Worker t.join().unwrap();
734*bb4ee6a4SAndroid Build Coastguard Worker }
735*bb4ee6a4SAndroid Build Coastguard Worker
736*bb4ee6a4SAndroid Build Coastguard Worker // Now that all submitters are finished, add NOPs to wake up any completers blocked on the
737*bb4ee6a4SAndroid Build Coastguard Worker // syscall.
738*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..NUM_COMPLETERS {
739*bb4ee6a4SAndroid Build Coastguard Worker uring
740*bb4ee6a4SAndroid Build Coastguard Worker .add_nop((NUM_SUBMITTERS * ITERATIONS + i) as UserData)
741*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
742*bb4ee6a4SAndroid Build Coastguard Worker }
743*bb4ee6a4SAndroid Build Coastguard Worker uring.submit().unwrap();
744*bb4ee6a4SAndroid Build Coastguard Worker
745*bb4ee6a4SAndroid Build Coastguard Worker for t in threads {
746*bb4ee6a4SAndroid Build Coastguard Worker t.join().unwrap();
747*bb4ee6a4SAndroid Build Coastguard Worker }
748*bb4ee6a4SAndroid Build Coastguard Worker
749*bb4ee6a4SAndroid Build Coastguard Worker // Make sure we didn't submit more entries than expected. Only the last few NOPs added to
750*bb4ee6a4SAndroid Build Coastguard Worker // wake up the completer threads may still be in the completion ring.
751*bb4ee6a4SAndroid Build Coastguard Worker assert!(uring.complete_ring.num_ready() <= NUM_COMPLETERS as u32);
752*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
753*bb4ee6a4SAndroid Build Coastguard Worker in_flight.lock().unsigned_abs() as u32 + uring.complete_ring.num_ready(),
754*bb4ee6a4SAndroid Build Coastguard Worker NUM_COMPLETERS as u32
755*bb4ee6a4SAndroid Build Coastguard Worker );
756*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(uring.submit_ring.lock().added, 0);
757*bb4ee6a4SAndroid Build Coastguard Worker }
758*bb4ee6a4SAndroid Build Coastguard Worker
759*bb4ee6a4SAndroid Build Coastguard Worker #[test]
restrict_ops()760*bb4ee6a4SAndroid Build Coastguard Worker fn restrict_ops() {
761*bb4ee6a4SAndroid Build Coastguard Worker const TEST_DATA: &[u8; 4] = b"foo!";
762*bb4ee6a4SAndroid Build Coastguard Worker
763*bb4ee6a4SAndroid Build Coastguard Worker let queue_size = 128;
764*bb4ee6a4SAndroid Build Coastguard Worker
765*bb4ee6a4SAndroid Build Coastguard Worker // Allow only Readv operation
766*bb4ee6a4SAndroid Build Coastguard Worker let mut restriction = URingAllowlist::new();
767*bb4ee6a4SAndroid Build Coastguard Worker restriction.allow_submit_operation(io_uring::URingOperation::Readv);
768*bb4ee6a4SAndroid Build Coastguard Worker
769*bb4ee6a4SAndroid Build Coastguard Worker let uring = URingContext::new(queue_size, Some(&restriction)).unwrap();
770*bb4ee6a4SAndroid Build Coastguard Worker
771*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; 4];
772*bb4ee6a4SAndroid Build Coastguard Worker let mut f = create_test_file(4);
773*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(TEST_DATA).unwrap();
774*bb4ee6a4SAndroid Build Coastguard Worker
775*bb4ee6a4SAndroid Build Coastguard Worker // add_read, which submits Readv, should succeed
776*bb4ee6a4SAndroid Build Coastguard Worker
777*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
778*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
779*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
780*bb4ee6a4SAndroid Build Coastguard Worker add_one_read(
781*bb4ee6a4SAndroid Build Coastguard Worker &uring,
782*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr(),
783*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
784*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
785*bb4ee6a4SAndroid Build Coastguard Worker Some(0),
786*bb4ee6a4SAndroid Build Coastguard Worker 0,
787*bb4ee6a4SAndroid Build Coastguard Worker )
788*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
789*bb4ee6a4SAndroid Build Coastguard Worker }
790*bb4ee6a4SAndroid Build Coastguard Worker let result = uring.wait().unwrap().next().unwrap();
791*bb4ee6a4SAndroid Build Coastguard Worker assert!(result.1.is_ok(), "uring read should succeed");
792*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&buf, TEST_DATA, "file should be read to buf");
793*bb4ee6a4SAndroid Build Coastguard Worker drop(f);
794*bb4ee6a4SAndroid Build Coastguard Worker
795*bb4ee6a4SAndroid Build Coastguard Worker // add_write should be rejected.
796*bb4ee6a4SAndroid Build Coastguard Worker
797*bb4ee6a4SAndroid Build Coastguard Worker let mut buf: [u8; 4] = TEST_DATA.to_owned(); // fake data, which should not be written
798*bb4ee6a4SAndroid Build Coastguard Worker let mut f = create_test_file(4);
799*bb4ee6a4SAndroid Build Coastguard Worker
800*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
801*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
802*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
803*bb4ee6a4SAndroid Build Coastguard Worker add_one_write(
804*bb4ee6a4SAndroid Build Coastguard Worker &uring,
805*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr(),
806*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
807*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_fd(),
808*bb4ee6a4SAndroid Build Coastguard Worker Some(0),
809*bb4ee6a4SAndroid Build Coastguard Worker 0,
810*bb4ee6a4SAndroid Build Coastguard Worker )
811*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
812*bb4ee6a4SAndroid Build Coastguard Worker }
813*bb4ee6a4SAndroid Build Coastguard Worker let result = uring.wait().unwrap().next().unwrap();
814*bb4ee6a4SAndroid Build Coastguard Worker assert!(result.1.is_err(), "uring write should fail");
815*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
816*bb4ee6a4SAndroid Build Coastguard Worker result.1.unwrap_err().raw_os_error(),
817*bb4ee6a4SAndroid Build Coastguard Worker Some(EACCES),
818*bb4ee6a4SAndroid Build Coastguard Worker "the error should be permission denied"
819*bb4ee6a4SAndroid Build Coastguard Worker );
820*bb4ee6a4SAndroid Build Coastguard Worker let mut result_f = vec![];
821*bb4ee6a4SAndroid Build Coastguard Worker f.seek(SeekFrom::Start(0)).unwrap(); // rewind to read from the beginning
822*bb4ee6a4SAndroid Build Coastguard Worker f.read_to_end(&mut result_f).unwrap();
823*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
824*bb4ee6a4SAndroid Build Coastguard Worker result_f.as_slice(),
825*bb4ee6a4SAndroid Build Coastguard Worker &[0, 0, 0, 0],
826*bb4ee6a4SAndroid Build Coastguard Worker "file should not be written and should stay empty"
827*bb4ee6a4SAndroid Build Coastguard Worker );
828*bb4ee6a4SAndroid Build Coastguard Worker }
829