From fbbc51aa3edf1475ea4be0ca2639bd37ba897f4f Mon Sep 17 00:00:00 2001
From: Matteo Croce <teknoraver@meta.com>
Date: Fri, 12 Dec 2025 19:28:54 -0800
Subject: [PATCH] cat: adjust the maximum data copied by copy_file_range

copy_cat() is doing unnecessary math to derive the maximum size allowed
by the copy_file_range() syscall. This calculates an excessively big
number which is 0x7FFFFFFFC0000000.
Linux syscalls have a much lower limit for single I/O operations,
which is defined in kernel as `INT_MAX - PAGE_SIZE`, so lower the limit
to that.

evidence of the limit is shown below:

$ uname -a
Linux v 6.17.5 #191 SMP Thu Oct 23 21:43:33 CEST 2025 x86_64 GNU/Linux

$ ll random
-rw-r--r-- 1 teknoraver users 8.0G Dec 12 19:19 random

$ strace -e copy_file_range src/cat random >random2
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 2147479552
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 2147479552
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 2147479552
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 2147479552
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 16384
copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 0
---
 src/cat.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/cat.c b/src/cat.c
index c02210301..811955459 100644
--- a/src/cat.c
+++ b/src/cat.c
@@ -503,10 +503,10 @@ cat (char *inbuf, idx_t insize, char *outbuf, idx_t outsize,
 static int
 copy_cat (void)
 {
-  /* Copy at most COPY_MAX bytes at a time; this is min
-     (SSIZE_MAX, SIZE_MAX) truncated to a value that is
-     surely aligned well.  */
-  ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
+  /* According to the read(2) man page, on Linux syscalls will transfer at most
+   * 0x7ffff000 (2,147,479,552) bytes on both 32-bit and 64-bit systems.
+   * In kernel this is defined as MAX_RW_COUNT which is INT_MAX - PAGE_SIZE. */
+  ssize_t copy_max = 0x7ffff000;
 
   /* copy_file_range does not support some cases, and it
      incorrectly returns 0 when reading from the proc file
-- 
2.50.1

