1
Fork 0

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.

Further, `NoneObtained` is not relevant in this context, so remove it.

Simply, determine what is input or output given the passed enum Unit.
This commit is contained in:
xstaticxgpx 2023-08-02 09:58:30 -04:00
parent d170833431
commit 2232fe8da3

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);