-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Limit I/O vector count on Unix #75005
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
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @hanna-kruppe (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
This is my first PR and I am sorry if I messed up the procedure. I also am rather unsure whether the overhead of |
library/std/src/sys/unix/fd.rs
Outdated
|
||
// 1024 is the default value on modern Linux systems | ||
// and hopefully more useful than `c_int::MAX`. | ||
lim = if ret > 0 { ret as usize } else { 1024 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we set errno=0
before sysconf
and check it again when ret == -1
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this and decided to not try to handle/propagate errors here and silently fallback to a default value instead as
- the value will not change for the lifetime of the process and I therefore want to report an error at most once to avoid repeatedly making a failing system call
- but I also would not like the first call to
FileDesc::write_vectored
to behave observably different by reporting the error fromlibc::sysconf
- thereby logging the error seems to be the only reasonable action in addition to the fallback but I did not find any infrastructure for logging within the standard library
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While not explicitly check for -1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest using 16 as the fallback value since that is the minimum guaranteed by POSIX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While not explicitly check for -1?
Accepting zero is not reasonable either as calls to write_vectored
would not make progress using that limit, hence the check for ret > 0
instead of checking ret == 0
and ret < 0
separately as the reaction is the same: use the fallback value.
I would suggest using 16 as the fallback value since that is the minimum guaranteed by POSIX.
Will do.
I don't really know anything about vectored I/O. r? @Amanieu maybe? |
On Linux #define UIO_MAXIOV 1024 |
Could you expand on the implication you see here? Do you mean that we should just hard code the constant and thereby avoid the call to |
Or put differently, isn't the |
library/std/src/sys/unix/fd.rs
Outdated
@@ -26,6 +27,35 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1; | |||
#[cfg(not(target_os = "macos"))] | |||
const READ_LIMIT: usize = libc::ssize_t::MAX as usize; | |||
|
|||
#[cfg(any(target_os = "linux", target_os = "macos"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be restricted to just Linux and macOS, all Unix-like OSes have limits on iovec length. Also it seems that all these targets have a definition of _SC_IOV_MAX
so there is no need to special case _SC_UIO_MAXIOV
for macOS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be restricted to just Linux and macOS, all Unix-like OSes have limits on iovec length.
What I was wondering here is whether #[cfg(unix)]
implies POSIX and hence allows relying on sysconf
and friends? Will change the code under that assumption...
so there is no need to special case _SC_UIO_MAXIOV for macOS.
I am admittedly just not knowledgeable on macOS and took that information from the linked bug report. Will change both to just use _SC_IOV_MAX
.
After thinking about it a bit, I think sticking to |
@Amanieu Is there anything that is still needs of a resolution? |
@bors r+ |
📌 Commit 10203e90f836f4ef9310e028d37b123ea54f9a38 has been approved by |
⌛ Testing commit 10203e90f836f4ef9310e028d37b123ea54f9a38 with merge 908d12265962911fcf0aeb6cedbacc693dd1c789... |
💔 Test failed - checks-actions |
@Amanieu The build failed as Redox OS' #[cfg(target_os = "redox")]
fn max_iov() -> usize { 16 } for this case? |
Sounds good! |
Both Linux and MacOS enforce limits on the vector count when performing vectored I/O via the readv and writev system calls and return EINVAL when these limits are exceeded. This changes the standard library to handle those limits as short reads and writes to avoid forcing its users to query these limits using platform specific mechanisms.
Keep the I/O vector count limit in a `SyncOnceCell` to avoid the overhead of repeatedly calling `sysconf` as these limits are guaranteed to not change during the lifetime of a process by POSIX.
All #[cfg(unix)] platforms follow the POSIX standard and define _SC_IOV_MAX so that we rely purely on POSIX semantics to determine the limits on I/O vector count.
Added it and build tested on |
Grepping |
@bors r+ |
📌 Commit 9073acd has been approved by |
@bors rollup=iffy |
☀️ Test successful - checks-actions, checks-azure |
…r=Amanieu Use IOV_MAX and UIO_MAXIOV constants in limit vectored I/O Also updates the libc dependency to 0.2.77 (from 0.2.74) as the constants were only recently added. Related rust-lang#68042, rust-lang#75005 r? @Amanieu (also reviewed rust-lang#75005)
…Amanieu Use IOV_MAX and UIO_MAXIOV constants in limit vectored I/O Also updates the libc dependency to 0.2.77 (from 0.2.74) as the constants were only recently added. Related rust-lang#68042, rust-lang#75005 r? `@Amanieu` (also reviewed rust-lang#75005)
Unix systems enforce limits on the vector count when performing vectored I/O via the readv and writev system calls and return EINVAL when these limits are exceeded. This changes the standard library to handle those limits as short reads and writes to avoid forcing its users to query these limits using platform specific mechanisms.
Fixes #68042