Rollup merge of #114373 - xstaticxgpx:dev, r=the8472

unix/kernel_copy.rs: copy_file_range_candidate allows empty output files

This is for https://github.com/rust-lang/rust/issues/114341

The `meta.len() > 0` condition here is intended for inputs only, ie. when input is in the `/proc` filesystem as documented.

That inaccurately included empty output files which are then shunted to the sendfile() routine leading to higher than nescessary IO util in some cases, specifically with CoW filesystems like btrfs.

Simply, determine what is input or output given the passed boolean.
This commit is contained in:
Matthias Krüger 2023-08-04 07:25:46 +02:00 committed by GitHub
commit 539fecb882
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -89,6 +89,12 @@ enum FdMeta {
NoneObtained,
}
#[derive(PartialEq)]
enum FdHandle {
Input,
Output,
}
impl FdMeta {
fn maybe_fifo(&self) -> bool {
match self {
@ -114,12 +120,14 @@ impl FdMeta {
}
}
fn copy_file_range_candidate(&self) -> bool {
fn copy_file_range_candidate(&self, f: FdHandle) -> bool {
match self {
// copy_file_range will fail on empty procfs files. `read` can determine whether EOF has been reached
// without extra cost and skip the write, thus there is no benefit in attempting copy_file_range
FdMeta::Metadata(meta) if meta.is_file() && meta.len() > 0 => true,
FdMeta::NoneObtained => true,
FdMeta::Metadata(meta) if f == FdHandle::Input && meta.is_file() && meta.len() > 0 => {
true
}
FdMeta::Metadata(meta) if f == FdHandle::Output && meta.is_file() => true,
_ => false,
}
}
@ -197,7 +205,9 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
written += flush()?;
let max_write = reader.min_limit();
if input_meta.copy_file_range_candidate() && output_meta.copy_file_range_candidate() {
if input_meta.copy_file_range_candidate(FdHandle::Input)
&& output_meta.copy_file_range_candidate(FdHandle::Output)
{
let result = copy_regular_files(readfd, writefd, max_write);
result.update_take(reader);