1- use io_uring:: { squeue:: Entry , IoUring } ;
1+ use io_uring:: { squeue:: Entry , IoUring , Probe } ;
22use mio:: unix:: SourceFd ;
33use slab:: Slab ;
44
@@ -38,6 +38,7 @@ impl State {
3838
3939pub ( crate ) struct UringContext {
4040 pub ( crate ) uring : Option < io_uring:: IoUring > ,
41+ pub ( crate ) probe : io_uring:: Probe ,
4142 pub ( crate ) ops : slab:: Slab < Lifecycle > ,
4243}
4344
@@ -46,6 +47,7 @@ impl UringContext {
4647 Self {
4748 ops : Slab :: new ( ) ,
4849 uring : None ,
50+ probe : Probe :: new ( ) ,
4951 }
5052 }
5153
@@ -57,6 +59,10 @@ impl UringContext {
5759 self . uring . as_mut ( ) . expect ( "io_uring not initialized" )
5860 }
5961
62+ pub ( crate ) fn is_opcode_supported ( & self , opcode : u8 ) -> bool {
63+ self . probe . is_supported ( opcode)
64+ }
65+
6066 /// Perform `io_uring_setup` system call, and Returns true if this
6167 /// actually initialized the io_uring.
6268 ///
@@ -68,7 +74,18 @@ impl UringContext {
6874 return Ok ( false ) ;
6975 }
7076
71- self . uring . replace ( IoUring :: new ( DEFAULT_RING_SIZE ) ?) ;
77+ let uring = IoUring :: new ( DEFAULT_RING_SIZE ) ?;
78+
79+ match uring. submitter ( ) . register_probe ( & mut self . probe ) {
80+ Ok ( _) => { }
81+ Err ( e) if e. raw_os_error ( ) == Some ( libc:: EINVAL ) => {
82+ // The kernel does not support IORING_REGISTER_PROBE.
83+ return Err ( io:: Error :: from_raw_os_error ( libc:: ENOSYS ) ) ;
84+ }
85+ Err ( e) => return Err ( e) ,
86+ }
87+
88+ self . uring . replace ( uring) ;
7289
7390 Ok ( true )
7491 }
@@ -182,12 +199,19 @@ impl Handle {
182199 }
183200
184201 /// Check if the io_uring context is initialized. If not, it will try to initialize it.
185- pub ( crate ) fn check_and_init ( & self ) -> io:: Result < bool > {
202+ /// Then, check if the provided opcode is supported.
203+ ///
204+ /// If both the context initialization succeeds and the opcode is supported,
205+ /// this returns `Ok(true)`.
206+ /// If either io_uring is unsupported or the opcode is unsupported,
207+ /// this returns `Ok(false)`.
208+ /// An error is returned if an io_uring syscall returns an unexpected error value.
209+ pub ( crate ) fn check_and_init ( & self , opcode : u8 ) -> io:: Result < bool > {
186210 match State :: from_usize ( self . uring_state . load ( Ordering :: Acquire ) ) {
187- State :: Uninitialized => match self . try_init ( ) {
188- Ok ( ( ) ) => {
211+ State :: Uninitialized => match self . try_init_and_check_opcode ( opcode ) {
212+ Ok ( opcode_supported ) => {
189213 self . set_uring_state ( State :: Initialized ) ;
190- Ok ( true )
214+ Ok ( opcode_supported )
191215 }
192216 // If the system doesn't support io_uring, we set the state to Unsupported.
193217 Err ( e) if e. raw_os_error ( ) == Some ( libc:: ENOSYS ) => {
@@ -205,18 +229,19 @@ impl Handle {
205229 Err ( e) => Err ( e) ,
206230 } ,
207231 State :: Unsupported => Ok ( false ) ,
208- State :: Initialized => Ok ( true ) ,
232+ State :: Initialized => Ok ( self . get_uring ( ) . lock ( ) . is_opcode_supported ( opcode ) ) ,
209233 }
210234 }
211235
212236 /// Initialize the io_uring context if it hasn't been initialized yet.
213- fn try_init ( & self ) -> io:: Result < ( ) > {
237+ /// Then, check whether the given opcode is supported.
238+ fn try_init_and_check_opcode ( & self , opcode : u8 ) -> io:: Result < bool > {
214239 let mut guard = self . get_uring ( ) . lock ( ) ;
215240 if guard. try_init ( ) ? {
216241 self . add_uring_source ( guard. ring ( ) . as_raw_fd ( ) ) ?;
217242 }
218243
219- Ok ( ( ) )
244+ Ok ( guard . is_opcode_supported ( opcode ) )
220245 }
221246
222247 /// Register an operation with the io_uring.
@@ -231,7 +256,7 @@ impl Handle {
231256 /// be valid for the entire duration of the operation, otherwise it may cause memory problems.
232257 pub ( crate ) unsafe fn register_op ( & self , entry : Entry , waker : Waker ) -> io:: Result < usize > {
233258 // Note: Maybe this check can be removed if upstream callers consistently use `check_and_init`.
234- if !self . check_and_init ( ) ? {
259+ if !self . check_and_init ( entry . get_opcode ( ) as u8 ) ? {
235260 return Err ( io:: Error :: from_raw_os_error ( libc:: ENOSYS ) ) ;
236261 }
237262
0 commit comments