On 03/04/2026 15:08, Pádraig Brady wrote:
On 02/04/2026 10:13, Collin Funk wrote:
Pádraig Brady <[email protected]> writes:

Cool. The read/write fallback should work.
I see this is now diagnosed:

    $ strace  -e inject=splice:error=EIO:when=3 \   src/cat /dev/zero > t.c

However errors on the writing splice are not always diagnosed:

    $ strace  -e inject=splice:error=EIO:when=4 \
      src/cat /dev/zero > t.c

I think think that just needs a clause like you have already done on the read 
side.

Oops, right. Done in the attached patch. I also simplified things to put
the error call in a single place after the "done" label. I find it
easier to follow that way.

As for tests, the odd and even straces above seem useful.

I also added those.

Another issue I noticed is that in yes.c we avoid the splice
if increase_pipe_size() returns 0.  cat.c should do the same.

The increase_pipe_size() function will never return 0. It returns a
reasonable guess if fcntl fails. I think that you were probably thinking
of pipe_splice_size() in src/yes.c. That function returns 0 if the pipe
size is smaller than the buffer.

Looking good.

As for the error message, we'll need to distinguish input from output
as the splice_cat() is dealing with both. With the attached tweaks I now get:

$ (trap '' PIPE; src/cat /dev/zero) | head -c1M >/dev/null
cat: splice error: Broken pipe

$ strace -o /dev/null -e inject=splice:error=ENOMEM:when=2 src/cat /dev/zero | cat 
> /dev/nullcat: splice error: Cannot allocate memory

$ strace -o /dev/null -e inject=splice:error=EIO:when=3 src/cat /dev/zero > 
/dev/null
cat: /dev/zero: Input/output error

$ strace -o /dev/null -e inject=splice:error=EIO:when=4 src/cat /dev/zero > 
/dev/null
cat: standard output: Input/output error

I also adjusted the test to ensure the strace injection is supported,
before checking for a specific error dependent on it.

Note we don't exit upon splice_cat failure,
which does lead to a change in behavior.
So one change to my previous patch is
I'd add an EXIT_FAILURE param to the error(..."standard error") call.

That still doesn't help when it's ambiguous though.
This shows we fallback to the write() path for subsequent files:

  $ cat /dev/zero | (trap '' PIPE; src/cat - - -) | head -c1 >/dev/null  cat: 
splice error: Broken pipe
  cat: write error: Broken pipe

Not huge issues, but it would be nice to avoid.
Specifically if output is gone, we'd like to avoid subsequent files.
Consider how this now hangs for example:

  $ yes | (trap '' PIPE; src/cat - /dev/tty) | head -c1 >/dev/null

A bit contrived I know.

Note this is only in the case where we don't create an intermediate pipe.
When we do have the intermediate pipe we can distinguish read errors
from write errors, so perhaps we should always do that.
Actually testing that here, gives faster operation anyway
(I guess due to the sizing of the pipes):

$ timeout 2 src/yes | pv -r | src/cat >/dev/null
Creating intermediate pipe
[36.9GiB/s]

$ timeout 2 src/yes | pv -r | src/cat >/dev/null
[22.6GiB/s]

cheers,
Padraig

Reply via email to