On 04/04/2026 03:27, Collin Funk wrote:
Attatched a v4 patch.

Since cat is such a fundamental tool, I think it's worth being extra defensive
by trying the read()/write() loop after the splice.
I've heard of cases where some fuse file systems lie about the size in stat,
while read() provides all the data.

Also it seems a bit wasteful to allocate large pipes in kernel mem,
for catting small files.

I think we could handle both these cases with the attached adjustment,
which avoids splice for small regular files, and tries read()/write()
after splice() always.  Note the size threshold was determined with:

  $ truncate -s $((32*1024)) mid  $ hyperfine -N 'src/cat-splice mid' 'src/cat 
mid'

Since we're not doing any more stats() to determine this info,
this should be more memory efficient and safer.

cheers,
Padraig
diff --git a/src/cat.c b/src/cat.c
index ed7e7ab3f..4b5516e06 100644
--- a/src/cat.c
+++ b/src/cat.c
@@ -864,14 +864,23 @@ main (int argc, char **argv)
             }
           else
             {
-              int splice_cat_status = splice_cat ();
-              if (splice_cat_status != 0)
+              /* Note 32768 was determined as the limit when splice
+                 starts to have a performance advantage.  It also
+                 excludes zero length files which may not be compatible
+                 with splice in some edge cases.  */
+              int splice_cat_status =
+                usable_st_size (&istat_buf) && istat_buf.st_size < 32768
+                ? 0 : splice_cat ();
+              if (splice_cat_status < 0)
                 {
                   inbuf = NULL;
-                  ok &= 0 < splice_cat_status;
+                  ok = false;
                 }
               else
                 {
+                  /* Note we try simple_cat() even if splice_cat() succeeded,
+                     to handle edge cases where splice finishes but read()
+                     still returns data (seen on some FUSE systems).  */
                   insize = MAX (insize, outsize);
                   inbuf = xalignalloc (page_size, insize);
                   ok &= simple_cat (inbuf, insize);

Reply via email to