about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-08-04 07:25:46 +0200
committerGitHub <noreply@github.com>2023-08-04 07:25:46 +0200
commit539fecb88284e36945da2bdf5673498fe385d6c4 (patch)
tree4042a3d938f0ba1c1ac271092b25d73f310945fb
parentfb150566637a4835d5d4554d4c6418606fc25e47 (diff)
parent2232fe8da3dcd4796e6db060ba61ba9c70a2a3f5 (diff)
downloadrust-539fecb88284e36945da2bdf5673498fe385d6c4.tar.gz
rust-539fecb88284e36945da2bdf5673498fe385d6c4.zip
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.
-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);