xref: /aosp_15_r20/external/crosvm/io_uring/tests/uring.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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