Hermit: fix readdir() - #158649
Conversation
This is also how it is done on other platforms.
This optimization was already partially in place, but not used. Other platforms already do this.
|
Thanks for the pull request, and welcome! The Rust Project is excited to review your changes, and you should hear from @joboet (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
Why was this reviewer chosen?The reviewer was selected based on:
|
| // The buffer. | ||
| buf: Box<[MaybeUninit<u8>]>, |
There was a problem hiding this comment.
This seems risky, the buffer must have a valid alignment for dirent64 (which has a u64 and a i64 field, and thus needs alignment), but a Box<[MaybeUninit<u8>]> doesn't guarantee any particular alignment.
There was a problem hiding this comment.
Sorry that it took me so long to react. This is a very valid point. I've now changed the type to Box<[MaybeUninit<dirent64>]>, which should ensure the correct alignment. This gives a little less flexibility in the sizing of the buffer, but should be fine in this context.
| } | ||
| let root = path.to_path_buf(); | ||
| let inner = Arc::new(InnerReadDir { root }); | ||
| let buf = GetdentsBuffer::with_capacity(DEFAULT_BUF_SIZE); |
There was a problem hiding this comment.
Can you guarantee that DEFAULT_BUF_SIZE is enough to hold any direntry? In any case, I'd decouple this definition (or rewrite it to max(DEFAULT_BUF_SIZE, MAX_DIRENTRY_SIZE)) to make sure that changes to DEFAULT_BUF_SIZE don't affect the correctness of ReadDir.
There was a problem hiding this comment.
Very good point. I've set it to usize::max(DEFAULT_BUF_SIZE, size_of::<dirent64>()), as the dirent64 already is sized in the hermit-abi to be large enough to hold the max filename size.
a2a9878 to
bcf9197
Compare
This comment has been minimized.
This comment has been minimized.
bcf9197 to
6856aad
Compare
|
Some changes occurred in match checking cc @Nadrieril
cc @rust-lang/miri Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Warning If you are changing how CI LLVM is built or linked, make sure to bump cc @jieyouxu These commits modify the If this was unintentional then you should revert the changes before this PR is merged. Some changes occurred to the CTFE machinery Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri This PR modifies If appropriate, please update
Any special-casing of Miri in the standard library requires review. cc @rust-lang/miri
cc @rust-lang/miri These commits modify the If this was unintentional then you should revert the changes before this PR is merged. |
This comment has been minimized.
This comment has been minimized.
|
Sorry, my rebase has gone wrong. I'm currently fixing this. |
Previously, we read all entries into a huge initialized buffer up front, which does not work correctly since on Hermit 0.12, getdents64 behaves more reasonable and does no longer fail on buffers which cannot hold all entries. Additionally, for each new entry, we started searching for the current position from the start instead of just saving the position directly. The new design uses a fixed-size uninitialized buffer that is read into as necessary. Co-authored-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
While Hermit does not return these yet, it will do so in the future.
6856aad to
0229444
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
I guess that all the CCs and the labels are a false alarm. My apologies for the noise. |
|
Looks reasonable! |
Hermit: fix `readdir()` On Hermit, the `sys_getdents` implementation was flawed, as it wasn't stateful. So the caller had to provide a buffer large enough to hold all `dirents` of the directory in question. Else it returns `EINVAL`. The current workaround used in Rust is to grow the buffer until it is sufficiently large. hermit-os/kernel#1738 fixes the behavior of `sys_getdents`. Hermit now keeps track of the directory position, and each new call to the `sys_getdents` provides the next entries. But this results in the current implementation in Rust Std being flawed: Because Hermit now returns a proper _readcount_, `read_dir` will only ever iterate over the first 512 bytes of directory entries, even if not all `dirent64`s are read. This PR fixes this with a proper implementation of the `getdents64` algorithm. Remark: This breaks compatibility with Hermit versions 0.11 and previous. We have discussed this in the Hermit team and have come to the conclusion that this is ok. We have released two newer "major" versions since, and Hermit is still in the development phase where we don't guarantee any stability and backwards compatibility in the kernel itself.
Hermit: fix `readdir()` On Hermit, the `sys_getdents` implementation was flawed, as it wasn't stateful. So the caller had to provide a buffer large enough to hold all `dirents` of the directory in question. Else it returns `EINVAL`. The current workaround used in Rust is to grow the buffer until it is sufficiently large. hermit-os/kernel#1738 fixes the behavior of `sys_getdents`. Hermit now keeps track of the directory position, and each new call to the `sys_getdents` provides the next entries. But this results in the current implementation in Rust Std being flawed: Because Hermit now returns a proper _readcount_, `read_dir` will only ever iterate over the first 512 bytes of directory entries, even if not all `dirent64`s are read. This PR fixes this with a proper implementation of the `getdents64` algorithm. Remark: This breaks compatibility with Hermit versions 0.11 and previous. We have discussed this in the Hermit team and have come to the conclusion that this is ok. We have released two newer "major" versions since, and Hermit is still in the development phase where we don't guarantee any stability and backwards compatibility in the kernel itself.
Rollup of 17 pull requests Successful merges: - #159014 ([rustdoc] Do not take `doc(cfg())` into account when filtering doctests) - #159130 (a bit optimize four-digit chunks in integer formatting) - #159592 (core: implement bounded random sampling) - #159898 (Add intrinsic-test alias and set sample rate) - #158247 (hermit/fs: Return `unsupported()` instead of `from_raw_os_error(22)`) - #158649 (Hermit: fix `readdir()` ) - #159049 (Avoid ICE in From/TryFrom cast suggestion when encountering HRTBs) - #160053 (test: add test suite for the 85681 issue) - #160087 (Add regression test for nested associated-type projection ICE) - #160090 (rustc_resolve: Further reduce mutability in resolver) - #160099 (Resolver: split module resolutions into local and external resolutions) - #160106 (Add suggestions for `must_implement_one_of`) - #160117 (Remove unnecessary format usage) - #160134 (Work around Wine bug 60084 by calling WSAStartup at most once) - #160142 (bootstrap: remove use-lld config alias) - #160148 (Rename `errors.rs` file to `diagnostics.rs` (15/N)) - #160151 (Mark a doctest as requiring unwinding)
Hermit: fix `readdir()` On Hermit, the `sys_getdents` implementation was flawed, as it wasn't stateful. So the caller had to provide a buffer large enough to hold all `dirents` of the directory in question. Else it returns `EINVAL`. The current workaround used in Rust is to grow the buffer until it is sufficiently large. hermit-os/kernel#1738 fixes the behavior of `sys_getdents`. Hermit now keeps track of the directory position, and each new call to the `sys_getdents` provides the next entries. But this results in the current implementation in Rust Std being flawed: Because Hermit now returns a proper _readcount_, `read_dir` will only ever iterate over the first 512 bytes of directory entries, even if not all `dirent64`s are read. This PR fixes this with a proper implementation of the `getdents64` algorithm. Remark: This breaks compatibility with Hermit versions 0.11 and previous. We have discussed this in the Hermit team and have come to the conclusion that this is ok. We have released two newer "major" versions since, and Hermit is still in the development phase where we don't guarantee any stability and backwards compatibility in the kernel itself.
Rollup of 18 pull requests Successful merges: - #159130 (a bit optimize four-digit chunks in integer formatting) - #159592 (core: implement bounded random sampling) - #159898 (Add intrinsic-test alias and set sample rate) - #158247 (hermit/fs: Return `unsupported()` instead of `from_raw_os_error(22)`) - #158649 (Hermit: fix `readdir()` ) - #159049 (Avoid ICE in From/TryFrom cast suggestion when encountering HRTBs) - #160053 (test: add test suite for the 85681 issue) - #160087 (Add regression test for nested associated-type projection ICE) - #160090 (rustc_resolve: Further reduce mutability in resolver) - #160099 (Resolver: split module resolutions into local and external resolutions) - #160106 (Add suggestions for `must_implement_one_of`) - #160117 (Remove unnecessary format usage) - #160134 (Work around Wine bug 60084 by calling WSAStartup at most once) - #160139 (iter: specialize Take::count using advance_by) - #160142 (bootstrap: remove use-lld config alias) - #160148 (Rename `errors.rs` file to `diagnostics.rs` (15/N)) - #160151 (Mark a doctest as requiring unwinding) - #160166 (Use correct feature gates for `f16`/`f128` `From` impls)
Hermit: fix `readdir()` On Hermit, the `sys_getdents` implementation was flawed, as it wasn't stateful. So the caller had to provide a buffer large enough to hold all `dirents` of the directory in question. Else it returns `EINVAL`. The current workaround used in Rust is to grow the buffer until it is sufficiently large. hermit-os/kernel#1738 fixes the behavior of `sys_getdents`. Hermit now keeps track of the directory position, and each new call to the `sys_getdents` provides the next entries. But this results in the current implementation in Rust Std being flawed: Because Hermit now returns a proper _readcount_, `read_dir` will only ever iterate over the first 512 bytes of directory entries, even if not all `dirent64`s are read. This PR fixes this with a proper implementation of the `getdents64` algorithm. Remark: This breaks compatibility with Hermit versions 0.11 and previous. We have discussed this in the Hermit team and have come to the conclusion that this is ok. We have released two newer "major" versions since, and Hermit is still in the development phase where we don't guarantee any stability and backwards compatibility in the kernel itself.
…uwer Rollup of 18 pull requests Successful merges: - #159898 (Add intrinsic-test alias and set sample rate) - #158247 (hermit/fs: Return `unsupported()` instead of `from_raw_os_error(22)`) - #158649 (Hermit: fix `readdir()` ) - #158693 (Add type-check to offload intrinisc calls) - #159049 (Avoid ICE in From/TryFrom cast suggestion when encountering HRTBs) - #159411 ([rustdoc] Correctly handle output options with --show-coverage) - #160053 (test: add test suite for the 85681 issue) - #160087 (Add regression test for nested associated-type projection ICE) - #160090 (rustc_resolve: Further reduce mutability in resolver) - #160099 (Resolver: split module resolutions into local and external resolutions) - #160106 (Add suggestions for `must_implement_one_of`) - #160117 (Remove unnecessary format usage) - #160134 (Work around Wine bug 60084 by calling WSAStartup at most once) - #160139 (iter: specialize Take::count using advance_by) - #160142 (bootstrap: remove use-lld config alias) - #160148 (Rename `errors.rs` file to `diagnostics.rs` (15/N)) - #160151 (Mark a doctest as requiring unwinding) - #160166 (Use correct feature gates for `f16`/`f128` `From` impls)
Rollup of 20 pull requests Successful merges: - #157669 (cfi: add diag mode support) - #158247 (hermit/fs: Return `unsupported()` instead of `from_raw_os_error(22)`) - #158649 (Hermit: fix `readdir()` ) - #158693 (Add type-check to offload intrinisc calls) - #159049 (Avoid ICE in From/TryFrom cast suggestion when encountering HRTBs) - #159411 ([rustdoc] Correctly handle output options with --show-coverage) - #160053 (test: add test suite for the 85681 issue) - #160087 (Add regression test for nested associated-type projection ICE) - #160090 (rustc_resolve: Further reduce mutability in resolver) - #160099 (Resolver: split module resolutions into local and external resolutions) - #160101 (Add missing `needs-unwind` annotation to `add-spawn-hook-reentrancy-159923` test) - #160106 (Add suggestions for `must_implement_one_of`) - #160117 (Remove unnecessary format usage) - #160134 (Work around Wine bug 60084 by calling WSAStartup at most once) - #160139 (iter: specialize Take::count using advance_by) - #160142 (bootstrap: remove use-lld config alias) - #160148 (Rename `errors.rs` file to `diagnostics.rs` (15/N)) - #160151 (Mark a doctest as requiring unwinding) - #160166 (Use correct feature gates for `f16`/`f128` `From` impls) - #160178 (Remove unused `va_start` intrinsic)
Rollup of 20 pull requests Successful merges: - #157669 (cfi: add diag mode support) - #158247 (hermit/fs: Return `unsupported()` instead of `from_raw_os_error(22)`) - #158649 (Hermit: fix `readdir()` ) - #158693 (Add type-check to offload intrinisc calls) - #159049 (Avoid ICE in From/TryFrom cast suggestion when encountering HRTBs) - #159411 ([rustdoc] Correctly handle output options with --show-coverage) - #160053 (test: add test suite for the 85681 issue) - #160087 (Add regression test for nested associated-type projection ICE) - #160090 (rustc_resolve: Further reduce mutability in resolver) - #160099 (Resolver: split module resolutions into local and external resolutions) - #160101 (Add missing `needs-unwind` annotation to `add-spawn-hook-reentrancy-159923` test) - #160106 (Add suggestions for `must_implement_one_of`) - #160117 (Remove unnecessary format usage) - #160134 (Work around Wine bug 60084 by calling WSAStartup at most once) - #160139 (iter: specialize Take::count using advance_by) - #160142 (bootstrap: remove use-lld config alias) - #160148 (Rename `errors.rs` file to `diagnostics.rs` (15/N)) - #160151 (Mark a doctest as requiring unwinding) - #160166 (Use correct feature gates for `f16`/`f128` `From` impls) - #160178 (Remove unused `va_start` intrinsic)
Rollup merge of #158649 - hermit-os:hermit-readdir, r=joboet Hermit: fix `readdir()` On Hermit, the `sys_getdents` implementation was flawed, as it wasn't stateful. So the caller had to provide a buffer large enough to hold all `dirents` of the directory in question. Else it returns `EINVAL`. The current workaround used in Rust is to grow the buffer until it is sufficiently large. hermit-os/kernel#1738 fixes the behavior of `sys_getdents`. Hermit now keeps track of the directory position, and each new call to the `sys_getdents` provides the next entries. But this results in the current implementation in Rust Std being flawed: Because Hermit now returns a proper _readcount_, `read_dir` will only ever iterate over the first 512 bytes of directory entries, even if not all `dirent64`s are read. This PR fixes this with a proper implementation of the `getdents64` algorithm. Remark: This breaks compatibility with Hermit versions 0.11 and previous. We have discussed this in the Hermit team and have come to the conclusion that this is ok. We have released two newer "major" versions since, and Hermit is still in the development phase where we don't guarantee any stability and backwards compatibility in the kernel itself.
On Hermit, the
sys_getdentsimplementation was flawed, as it wasn't stateful. So the caller had to provide a buffer large enough to hold alldirentsof the directory in question. Else it returnsEINVAL. The current workaround used in Rust is to grow the buffer until it is sufficiently large.hermit-os/kernel#1738 fixes the behavior of
sys_getdents. Hermit now keeps track of the directory position, and each new call to thesys_getdentsprovides the next entries.But this results in the current implementation in Rust Std being flawed: Because Hermit now returns a proper readcount,
read_dirwill only ever iterate over the first 512 bytes of directory entries, even if not alldirent64s are read.This PR fixes this with a proper implementation of the
getdents64algorithm.Remark:
This breaks compatibility with Hermit versions 0.11 and previous. We have discussed this in the Hermit team and have come to the conclusion that this is ok. We have released two newer "major" versions since, and Hermit is still in the development phase where we don't guarantee any stability and backwards compatibility in the kernel itself.