fs: implement tokio::fs::create_dir[_all] via io_uring#7847
Open
tahmid-23 wants to merge 4 commits intotokio-rs:masterfrom
Open
fs: implement tokio::fs::create_dir[_all] via io_uring#7847tahmid-23 wants to merge 4 commits intotokio-rs:masterfrom
tahmid-23 wants to merge 4 commits intotokio-rs:masterfrom
Conversation
martin-g
reviewed
Mar 4, 2026
Member
martin-g
left a comment
There was a problem hiding this comment.
The build fails with:
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> tokio/src/fs/create_dir.rs:60:12
|
60 | if driver_handle.check_and_init(io_uring::opcode::MkDirAt::CODE)? {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future<Output = std::result::Result<bool, std::io::Error>>`
|
= help: the trait `std::ops::Try` is not implemented for `impl std::future::Future<Output = std::result::Result<bool, std::io::Error>>`
help: consider `await`ing on the `Future`
martin-g
reviewed
Mar 4, 2026
| { | ||
| let parent_bytes = &path_bytes[..separator_pos]; | ||
| let parent_str = OsStr::from_bytes(parent_bytes); | ||
| let parent_path = Path::new(parent_str); |
| // | ||
| // TODO: We're attempting to create all directories sequentially. | ||
| // This would benefit from batching. | ||
| for (separator_pos, _) in path_bytes |
| Ok(()) => Ok(true), | ||
| Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(false), | ||
| // TODO: replace with uring-based statx | ||
| Err(_) if crate::fs::metadata(path).await?.is_dir() => Ok(true), |
Member
There was a problem hiding this comment.
metadata(path).await? may hide the original error (the ignored one in Err(_))
Suggested change
| Err(_) if crate::fs::metadata(path).await?.is_dir() => Ok(true), | |
| Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => { | |
| if crate::fs::metadata(path).await?.is_dir() { | |
| Ok(true) | |
| } else { | |
| Err(e) | |
| } | |
| } |
something like this should be better
| match Op::mkdir(path)?.await { | ||
| Ok(()) => Ok(()), | ||
| // TODO: replace with uring-based statx | ||
| Err(_) if crate::fs::metadata(path).await?.is_dir() => Ok(()), |
| feature = "rt", | ||
| feature = "fs", | ||
| target_os = "linux" | ||
| ))] |
Member
There was a problem hiding this comment.
This cfg guard is not really needed.
This module is already conditionally used with cfg_io_uring! in mod.rs
Comment on lines
+7
to
+8
| use std::io; | ||
| use std::io::Error; |
Member
There was a problem hiding this comment.
Suggested change
| use std::io; | |
| use std::io::Error; | |
| use std::io::{self, Error}; |
| use tokio_test::assert_pending; | ||
| use tokio_util::task::TaskTracker; | ||
|
|
||
| fn multi_rt(n: usize) -> Box<dyn Fn() -> Runtime> { |
Member
There was a problem hiding this comment.
Those seem copied from one of the other tests.
Let's extract them into a helper module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
io_uring + mkdirat()
As opposed to std's implementation of recursive directory creation, this does not use a recursive function to create parent directories. Instead, it iterates over positions of
/(the unix / linux path separator), first failing to create parent directories until success, and then creating all children.This prevents us from allocating a boxed future for each recursive function call.
It does have the minimal overhead of needing to find the
/positions an additional time in the second forward iterator. We could save this by allocating aVecof/positions; I don't necessarily know what's better.