Skip to content

fs: add io_uring open operation #7321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
145 changes: 130 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,12 @@ 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.
///
/// # Examples
///
/// ```no_run
Expand All @@ -386,17 +460,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 +521,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 +560,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 +760,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