Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2620f14
rt: add infrastructure code for io_uring
mox692 May 8, 2025
437e414
fs: add io_uring `open` operation
mox692 May 8, 2025
05239cc
make ci work
mox692 May 8, 2025
d0dc6b2
add benchmark
mox692 May 11, 2025
2edfec8
Resolve conflict with changes introduced in #7320
mox692 May 22, 2025
c491ccb
rt: add check for uring availability at runtime
mox692 May 21, 2025
ea9d152
Remove LazyUring
mox692 May 22, 2025
2d143a1
Merge branch 'mox692/uring_dynamic_check' into mox692/iouring_add_open
mox692 May 22, 2025
d659626
fallback when io_uring is not available
mox692 May 23, 2025
15542a7
rt: add check for io_uring availability at runtime
mox692 May 21, 2025
c037b3d
Merge branch 'mox692/uring_dynamic_check' into mox692/iouring_add_open
mox692 May 24, 2025
8da05c3
rt: add check for io_uring availability at runtime
mox692 May 21, 2025
df5e117
Merge branch 'mox692/uring_dynamic_check' into mox692/iouring_add_open
mox692 May 24, 2025
d3567c9
Merge remote-tracking branch 'upstream/master' into mox692/iouring_ad…
mox692 Jun 12, 2025
c80c3ca
revert temporary ci change
mox692 Jun 13, 2025
7483401
handle cancel for open
mox692 Jun 13, 2025
26485c8
updates
mox692 Jun 14, 2025
2ec8482
apply reivew: add verification step in CI to check if uring is supported
mox692 Jun 19, 2025
32638f0
apply review: remove unreachable code path
mox692 Jun 20, 2025
e981341
apply review: mention that io_uring is experimental
mox692 Jun 23, 2025
05e79bf
Merge remote-tracking branch 'origin/master' into mox692/iouring_add_…
mox692 Jun 25, 2025
fdba9e2
Update tokio/tests/fs_uring.rs
mox692 Jun 25, 2025
a31cffd
apply review: use task tracker
mox692 Jun 26, 2025
dff8711
apply review: update test to use shutdown_timeout
mox692 Jun 30, 2025
db5e844
Merge branch 'master' into mox692/iouring_add_open
mox692 Jul 5, 2025
1405ee8
address review: remove several #[allow(dead_code)]
mox692 Jul 26, 2025
6dd50a3
address review: use yield_now
mox692 Jul 26, 2025
62dc6dc
add `--cfg tokio_uring` when docs build
mox692 Jul 26, 2025
b04fde9
Merge branch 'master' into mox692/iouring_add_open
mox692 Jul 26, 2025
76d1537
fix drop implementation of UringContext
mox692 Jul 26, 2025
2b4058e
Merge branch 'master' into mox692/iouring_add_open
mox692 Jul 27, 2025
15e5b11
Merge remote-tracking branch 'upstream/master' into mox692/iouring_ad…
mox692 Aug 5, 2025
da0175b
update test so that old kernel test wouldn't fail
mox692 Aug 5, 2025
94b2df0
Merge remote-tracking branch 'origin/master' into mox692/iouring_add_…
mox692 Aug 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,17 @@ jobs:
include:
- os: ubuntu-latest
steps:
- name: check if io-uring is supported in the CI environment
run: |
# Try to read the io-uring setting in the kernel config file.
# https://github.com/torvalds/linux/blob/75f5f23f8787c5e184fcb2fbcd02d8e9317dc5e7/init/Kconfig#L1782-L1789
CONFIG_FILE="/boot/config-$(uname -r)"
echo "Checking $CONFIG_FILE for io-uring support"
if ! grep -q "CONFIG_IO_URING=y" "$CONFIG_FILE"; then
echo "Error: io_uring is not supported"
exit 1
fi

- uses: actions/checkout@v4
- name: Install Rust ${{ env.rust_stable }}
uses: dtolnay/rust-toolchain@stable
Expand Down
5 changes: 3 additions & 2 deletions tokio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ features = [
[dev-dependencies]
tokio-test = { version = "0.4.0", path = "../tokio-test" }
tokio-stream = { version = "0.1", path = "../tokio-stream" }
tokio-util = { version = "0.7", path = "../tokio-util", features = ["rt"] }
futures = { version = "0.3.0", features = ["async-await"] }
mockall = "0.13.0"
async-stream = "0.3"
Expand Down Expand Up @@ -164,10 +165,10 @@ tracing-mock = "= 0.1.0-beta.1"
[package.metadata.docs.rs]
all-features = true
# enable unstable features in the documentation
rustdoc-args = ["--cfg", "docsrs", "--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"]
rustdoc-args = ["--cfg", "docsrs", "--cfg", "tokio_unstable", "--cfg", "tokio_taskdump", "--cfg", "tokio_uring"]
# it's necessary to _also_ pass `--cfg tokio_unstable` and `--cfg tokio_taskdump`
# to rustc, or else dependencies will not be enabled, and the docs build will fail.
rustc-args = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"]
rustc-args = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump", "--cfg", "tokio_uring"]

[package.metadata.playground]
features = ["full", "test-util"]
Expand Down
3 changes: 3 additions & 0 deletions tokio/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ pub use self::metadata::metadata;

mod open_options;
pub use self::open_options::OpenOptions;
cfg_tokio_uring! {
pub(crate) use self::open_options::UringOpenOptions;
}

mod read;
pub use self::read::read;
Expand Down
148 changes: 133 additions & 15 deletions tokio/src/fs/open_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ use crate::fs::{asyncify, File};
use std::io;
use std::path::Path;

cfg_tokio_uring! {
mod uring_open_options;
pub(crate) use uring_open_options::UringOpenOptions;
use crate::runtime::driver::op::Op;
}

#[cfg(test)]
mod mock_open_options;
#[cfg(test)]
Expand Down Expand Up @@ -79,7 +85,16 @@ use std::os::windows::fs::OpenOptionsExt;
/// }
/// ```
#[derive(Clone, Debug)]
pub struct OpenOptions(StdOpenOptions);
pub struct OpenOptions {
inner: Kind,
}

#[derive(Debug, Clone)]
enum Kind {
Std(StdOpenOptions),
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Uring(UringOpenOptions),
}

impl OpenOptions {
/// Creates a blank new set of options ready for configuration.
Expand All @@ -99,7 +114,12 @@ impl OpenOptions {
/// let future = options.read(true).open("foo.txt");
/// ```
pub fn new() -> OpenOptions {
OpenOptions(StdOpenOptions::new())
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
let inner = Kind::Uring(UringOpenOptions::new());
#[cfg(not(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux")))]
let inner = Kind::Std(StdOpenOptions::new());

OpenOptions { inner }
}

/// Sets the option for read access.
Expand Down Expand Up @@ -128,7 +148,15 @@ impl OpenOptions {
/// }
/// ```
pub fn read(&mut self, read: bool) -> &mut OpenOptions {
self.0.read(read);
match &mut self.inner {
Kind::Std(opts) => {
opts.read(read);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.read(read);
}
}
self
}

Expand Down Expand Up @@ -158,7 +186,15 @@ impl OpenOptions {
/// }
/// ```
pub fn write(&mut self, write: bool) -> &mut OpenOptions {
self.0.write(write);
match &mut self.inner {
Kind::Std(opts) => {
opts.write(write);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.write(write);
}
}
self
}

Expand Down Expand Up @@ -217,7 +253,15 @@ impl OpenOptions {
/// }
/// ```
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
self.0.append(append);
match &mut self.inner {
Kind::Std(opts) => {
opts.append(append);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.append(append);
}
}
self
}

Expand Down Expand Up @@ -250,7 +294,15 @@ impl OpenOptions {
/// }
/// ```
pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
self.0.truncate(truncate);
match &mut self.inner {
Kind::Std(opts) => {
opts.truncate(truncate);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.truncate(truncate);
}
}
self
}

Expand Down Expand Up @@ -286,7 +338,15 @@ impl OpenOptions {
/// }
/// ```
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
self.0.create(create);
match &mut self.inner {
Kind::Std(opts) => {
opts.create(create);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.create(create);
}
}
self
}

Expand Down Expand Up @@ -329,7 +389,15 @@ impl OpenOptions {
/// }
/// ```
pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
self.0.create_new(create_new);
match &mut self.inner {
Kind::Std(opts) => {
opts.create_new(create_new);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.create_new(create_new);
}
}
self
}

Expand Down Expand Up @@ -366,6 +434,15 @@ impl OpenOptions {
/// open files, too long filename, too many symbolic links in the
/// specified path (Unix-like systems only), etc.
///
/// # io_uring support
///
/// On Linux, you can also use `io_uring` for executing system calls.
/// To enable `io_uring`, you need to specify the `--cfg tokio_uring` flag
/// at compile time and set the `Builder::enable_io_uring` runtime option.
///
/// Support for `io_uring` is currently experimental, so its behavior may
/// change or it may be removed in future versions.
///
/// # Examples
///
/// ```no_run
Expand All @@ -386,17 +463,36 @@ impl OpenOptions {
/// [`Other`]: std::io::ErrorKind::Other
/// [`PermissionDenied`]: std::io::ErrorKind::PermissionDenied
pub async fn open(&self, path: impl AsRef<Path>) -> io::Result<File> {
match &self.inner {
Kind::Std(opts) => Self::std_open(opts, path).await,
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
let handle = crate::runtime::Handle::current();
let driver_handle = handle.inner.driver().io();

if driver_handle.check_and_init()? {
Op::open(path.as_ref(), opts)?.await
} else {
let opts = opts.clone().into();
Self::std_open(&opts, path).await
}
}
}
}

async fn std_open(opts: &StdOpenOptions, path: impl AsRef<Path>) -> io::Result<File> {
let path = path.as_ref().to_owned();
let opts = self.0.clone();
let opts = opts.clone();

let std = asyncify(move || opts.open(path)).await?;
Ok(File::from_std(std))
}

/// Returns a mutable reference to the underlying `std::fs::OpenOptions`
#[cfg(any(windows, unix))]
#[cfg(windows)]
pub(super) fn as_inner_mut(&mut self) -> &mut StdOpenOptions {
&mut self.0
match &mut self.inner {
Kind::Std(ref mut opts) => opts,
}
}
}

Expand Down Expand Up @@ -428,7 +524,15 @@ feature! {
/// }
/// ```
pub fn mode(&mut self, mode: u32) -> &mut OpenOptions {
self.as_inner_mut().mode(mode);
match &mut self.inner {
Kind::Std(opts) => {
opts.mode(mode);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.mode(mode);
}
}
self
}

Expand Down Expand Up @@ -459,7 +563,15 @@ feature! {
/// }
/// ```
pub fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags);
match &mut self.inner {
Kind::Std(opts) => {
opts.custom_flags(flags);
}
#[cfg(all(tokio_uring, feature = "rt", feature = "fs", target_os = "linux"))]
Kind::Uring(opts) => {
opts.custom_flags(flags);
}
}
self
}
}
Expand Down Expand Up @@ -651,7 +763,13 @@ cfg_windows! {

impl From<StdOpenOptions> for OpenOptions {
fn from(options: StdOpenOptions) -> OpenOptions {
OpenOptions(options)
OpenOptions {
inner: Kind::Std(options),
// TODO: Add support for converting `StdOpenOptions` to `UringOpenOptions`
// if user enables the `--cfg tokio_uring`. It is blocked by:
// * https://github.com/rust-lang/rust/issues/74943
// * https://github.com/rust-lang/rust/issues/76801
}
}
}

Expand Down
Loading
Loading