about summary refs log tree commit diff
path: root/library/std
diff options
context:
space:
mode:
authorxstaticxgpx <gabe@gabe.tech>2023-08-02 09:58:30 -0400
committerxstaticxgpx <gabe@gabe.tech>2023-08-03 19:27:45 -0400
commit2232fe8da3dcd4796e6db060ba61ba9c70a2a3f5 (patch)
treef7331700d2cae885de07f37bcb932f3b5189f125 /library/std
parentd1708334312f654204edd21b3e93cf29da847187 (diff)
downloadrust-2232fe8da3dcd4796e6db060ba61ba9c70a2a3f5.tar.gz
rust-2232fe8da3dcd4796e6db060ba61ba9c70a2a3f5.zip
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.
Diffstat (limited to 'library/std')
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs18
1 files changed, 14 insertions, 4 deletions
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 7d49bbdcbe0..4d17a1b0002 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -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);