diff --git a/.github/workflows/uring-kernel-version-test.yml b/.github/workflows/uring-kernel-version-test.yml index 14170f36c8b..bc90ea0a2f6 100644 --- a/.github/workflows/uring-kernel-version-test.yml +++ b/.github/workflows/uring-kernel-version-test.yml @@ -40,6 +40,8 @@ jobs: make defconfig make -j$(nproc) + # We are running tests also on a Kernel version that does not support io_uring + # to check if the fallback mechanism works - name: Generate test binaries with io_uring enabled run: | # Build both integration (tokio/tests/) and unit (e.g., tokio/src/fs/file/tests.rs) tests with io_uring enabled diff --git a/tokio/tests/fs_uring_cancel_open.rs b/tokio/tests/fs_uring_cancel_open.rs index 5f204020564..989f9525d42 100644 --- a/tokio/tests/fs_uring_cancel_open.rs +++ b/tokio/tests/fs_uring_cancel_open.rs @@ -13,10 +13,21 @@ use std::fs; use std::future::poll_fn; use std::task::Poll; use tempfile::NamedTempFile; +use tokio_test::assert_pending; + +use crate::support::io_uring::io_uring_supported; + +mod support { + pub(crate) mod io_uring; +} // see: https://github.com/tokio-rs/tokio/issues/7979 #[tokio::test] async fn file_descriptors_are_closed_when_cancelling_open_op() { + if !io_uring_supported() { + return; + } + let tmp = NamedTempFile::new().unwrap(); let path = tmp.path().to_path_buf(); @@ -37,10 +48,8 @@ async fn file_descriptors_are_closed_when_cancelling_open_op() { let fut = opt.open(&path); // If io_uring is enabled (and not falling back to the thread pool), - // the first poll should return Pending. We don't check if the result - // is actually pending because we run some checks on old kernel that - // do not support uring. - let _pending = Box::pin(fut).poll_unpin(cx); + // the first poll should return Pending. + assert_pending!(Box::pin(fut).poll_unpin(cx)); tx.send(()).unwrap(); diff --git a/tokio/tests/fs_uring_completed_then_dropped_before_repoll.rs b/tokio/tests/fs_uring_completed_then_dropped_before_repoll.rs index 359e298b53a..a3debe47beb 100644 --- a/tokio/tests/fs_uring_completed_then_dropped_before_repoll.rs +++ b/tokio/tests/fs_uring_completed_then_dropped_before_repoll.rs @@ -6,6 +6,11 @@ target_os = "linux" ))] +mod support { + pub(crate) mod io_uring; +} + +use std::fmt::Debug; use std::fs; use std::future::Future; use std::path::PathBuf; @@ -16,6 +21,9 @@ use std::time::Duration; use tempfile::NamedTempFile; use tokio::sync::mpsc::{unbounded_channel, UnboundedSender}; use tokio::time::timeout; +use tokio_test::assert_pending; + +use crate::support::io_uring::io_uring_supported; /// Count currently-open fds in this process. fn fd_count() -> usize { @@ -42,14 +50,17 @@ struct PollOpenOnceThenNeverRepoll { polled_once: bool, } -impl Future for PollOpenOnceThenNeverRepoll { - type Output = (); +impl Future for PollOpenOnceThenNeverRepoll +where + F::Output: Debug, +{ + type Output = F::Output; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if !self.polled_once { - // We don't check if the result is actually pending because - // we run some checks on old kernel that do not support uring. - let _pending = self.inner.as_mut().poll(cx); + // If io_uring is enabled (and not falling back to the thread pool), + // the first poll should return Pending. + assert_pending!(self.inner.as_mut().poll(cx)); self.polled_once = true; self.first_poll_tx.take().unwrap().send(()).unwrap(); @@ -80,7 +91,7 @@ async fn completed_then_dropped_before_repoll(path: PathBuf) { second_poll_tx: Some(second_tx), polled_once: false, } - .await; + .await }); // Wait until the inner open has been polled once and registered with io_uring. @@ -98,6 +109,10 @@ async fn completed_then_dropped_before_repoll(path: PathBuf) { #[test] fn uring_completed_then_dropped() { + if !io_uring_supported() { + return; + } + let rt = tokio::runtime::Builder::new_multi_thread() .worker_threads(1) .enable_all() diff --git a/tokio/tests/fs_uring_runtime_shutdown.rs b/tokio/tests/fs_uring_runtime_shutdown.rs index 429cfce1884..62f0a17e3f1 100644 --- a/tokio/tests/fs_uring_runtime_shutdown.rs +++ b/tokio/tests/fs_uring_runtime_shutdown.rs @@ -14,10 +14,21 @@ use std::future::poll_fn; use std::task::Poll; use tempfile::NamedTempFile; use tokio::runtime::Builder; +use tokio_test::assert_pending; + +use crate::support::io_uring::io_uring_supported; + +mod support { + pub(crate) mod io_uring; +} // see: https://github.com/tokio-rs/tokio/issues/7979 #[test] fn shutdown_runtime_while_performing_io_uring_ops() { + if !io_uring_supported() { + return; + } + let tmp = NamedTempFile::new().unwrap(); let path = tmp.path().to_path_buf(); @@ -41,10 +52,8 @@ fn shutdown_runtime_while_performing_io_uring_ops() { let fut = opt.open(&path); // If io_uring is enabled (and not falling back to the thread pool), - // the first poll should return Pending. We don't check if the result - // is actually a pending because we run some CI checks based on old - // kernels that don't support uring. - let _pending = Box::pin(fut).poll_unpin(cx); + // the first poll should return Pending. + assert_pending!(Box::pin(fut).poll_unpin(cx)); tx.send(()).unwrap(); diff --git a/tokio/tests/support/io_uring.rs b/tokio/tests/support/io_uring.rs new file mode 100644 index 00000000000..affb2f833be --- /dev/null +++ b/tokio/tests/support/io_uring.rs @@ -0,0 +1,24 @@ +#![cfg(all( + tokio_unstable, + feature = "io-uring", + feature = "rt", + feature = "fs", + target_os = "linux" +))] + +use io_uring::IoUring; + +// Currently, we are running some of the tests on Kernels where io_uring is not supported +// to check if the fallback mechanism works, this comes with the limitation that we are not +// able to run some checks (e.g., asserting a poll returns pending). This utiliy function +// is useful when we want to run a test only in Linux targets where io_uring is supported. +pub fn io_uring_supported() -> bool { + match IoUring::new(256) { + Ok(_) => true, + // The Kernel does not support io-uring + Err(e) if e.raw_os_error() == Some(libc::ENOSYS) => false, + Err(_) => unreachable!( + "The target should either support io_uring or return ENOSYS if not supported" + ), + } +}